github.com/google/cadvisor@v0.49.1/container/containerd/factory.go (about) 1 // Copyright 2017 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package containerd 16 17 import ( 18 "flag" 19 "fmt" 20 "path" 21 "regexp" 22 "strings" 23 24 "golang.org/x/net/context" 25 "k8s.io/klog/v2" 26 27 "github.com/google/cadvisor/container" 28 "github.com/google/cadvisor/container/libcontainer" 29 "github.com/google/cadvisor/fs" 30 info "github.com/google/cadvisor/info/v1" 31 "github.com/google/cadvisor/watcher" 32 ) 33 34 var ArgContainerdEndpoint = flag.String("containerd", "/run/containerd/containerd.sock", "containerd endpoint") 35 var ArgContainerdNamespace = flag.String("containerd-namespace", "k8s.io", "containerd namespace") 36 37 var containerdEnvMetadataWhiteList = flag.String("containerd_env_metadata_whitelist", "", "DEPRECATED: this flag will be removed, please use `env_metadata_whitelist`. A comma-separated list of environment variable keys matched with specified prefix that needs to be collected for containerd containers") 38 39 // The namespace under which containerd aliases are unique. 40 const k8sContainerdNamespace = "containerd" 41 42 // Regexp that identifies containerd cgroups, containers started with 43 // --cgroup-parent have another prefix than 'containerd' 44 var containerdCgroupRegexp = regexp.MustCompile(`([a-z0-9]{64})`) 45 46 type containerdFactory struct { 47 machineInfoFactory info.MachineInfoFactory 48 client ContainerdClient 49 version string 50 // Information about the mounted cgroup subsystems. 51 cgroupSubsystems map[string]string 52 // Information about mounted filesystems. 53 fsInfo fs.FsInfo 54 includedMetrics container.MetricSet 55 } 56 57 func (f *containerdFactory) String() string { 58 return k8sContainerdNamespace 59 } 60 61 func (f *containerdFactory) NewContainerHandler(name string, metadataEnvAllowList []string, inHostNamespace bool) (handler container.ContainerHandler, err error) { 62 client, err := Client(*ArgContainerdEndpoint, *ArgContainerdNamespace) 63 if err != nil { 64 return 65 } 66 67 containerdMetadataEnvAllowList := strings.Split(*containerdEnvMetadataWhiteList, ",") 68 69 // prefer using the unified metadataEnvAllowList 70 if len(metadataEnvAllowList) != 0 { 71 containerdMetadataEnvAllowList = metadataEnvAllowList 72 } 73 74 return newContainerdContainerHandler( 75 client, 76 name, 77 f.machineInfoFactory, 78 f.fsInfo, 79 f.cgroupSubsystems, 80 inHostNamespace, 81 containerdMetadataEnvAllowList, 82 f.includedMetrics, 83 ) 84 } 85 86 // Returns the containerd ID from the full container name. 87 func ContainerNameToContainerdID(name string) string { 88 id := path.Base(name) 89 if matches := containerdCgroupRegexp.FindStringSubmatch(id); matches != nil { 90 return matches[1] 91 } 92 return id 93 } 94 95 // isContainerName returns true if the cgroup with associated name 96 // corresponds to a containerd container. 97 func isContainerName(name string) bool { 98 // TODO: May be check with HasPrefix ContainerdNamespace 99 if strings.HasSuffix(name, ".mount") { 100 return false 101 } 102 return containerdCgroupRegexp.MatchString(path.Base(name)) 103 } 104 105 // Containerd can handle and accept all containerd created containers 106 func (f *containerdFactory) CanHandleAndAccept(name string) (bool, bool, error) { 107 // if the container is not associated with containerd, we can't handle it or accept it. 108 if !isContainerName(name) { 109 return false, false, nil 110 } 111 // Check if the container is known to containerd and it is running. 112 id := ContainerNameToContainerdID(name) 113 // If container and task lookup in containerd fails then we assume 114 // that the container state is not known to containerd 115 ctx := context.Background() 116 _, err := f.client.LoadContainer(ctx, id) 117 if err != nil { 118 return false, false, fmt.Errorf("failed to load container: %v", err) 119 } 120 121 return true, true, nil 122 } 123 124 func (f *containerdFactory) DebugInfo() map[string][]string { 125 return map[string][]string{} 126 } 127 128 // Register root container before running this function! 129 func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error { 130 client, err := Client(*ArgContainerdEndpoint, *ArgContainerdNamespace) 131 if err != nil { 132 return fmt.Errorf("unable to create containerd client: %v", err) 133 } 134 135 containerdVersion, err := client.Version(context.Background()) 136 if err != nil { 137 return fmt.Errorf("failed to fetch containerd client version: %v", err) 138 } 139 140 cgroupSubsystems, err := libcontainer.GetCgroupSubsystems(includedMetrics) 141 if err != nil { 142 return fmt.Errorf("failed to get cgroup subsystems: %v", err) 143 } 144 145 klog.V(1).Infof("Registering containerd factory") 146 f := &containerdFactory{ 147 cgroupSubsystems: cgroupSubsystems, 148 client: client, 149 fsInfo: fsInfo, 150 machineInfoFactory: factory, 151 version: containerdVersion, 152 includedMetrics: includedMetrics, 153 } 154 155 container.RegisterContainerHandlerFactory(f, []watcher.ContainerWatchSource{watcher.Raw}) 156 return nil 157 }