内容简介:Kubelet日志中不停的出现下面的错误:又是和cgroup有关的错误,见到cgroup就头大,之前学习过cgroup(Kubernetes版本1.9.11。
说明
Kubelet日志中不停的出现下面的错误:
Jan 25 ... summary.go:92] Failed to get system container stats for "/systemd/system.slice": failed to get cgroup stats for "/systemd/system.slice": failed to get container info for "/systemd/system.slice": unknown container "/systemd/system.slice" Jan 25 ... summary.go:92] Failed to get system container stats for "/systemd/system.slice": failed to get cgroup stats for "/systemd/system.slice": failed to get container info for "/systemd/system.slice": unknown container "/systemd/system.slice"
又是和cgroup有关的错误,见到cgroup就头大,之前学习过cgroup( 《cgroup:linux的cgroup的使用》 ),但是一直没形成很清晰的认识,借着排查这个问题的机会深入了解一下。
Kubernetes版本1.9.11。
扫代码
kubelet版本是1.9.11,错误日志来自这里:
// pkg/kubelet/server/stats/summary.go // Get provides a new Summary with the stats from Kubelet. func (sp *summaryProviderImpl) Get() (*statsapi.Summary, error) { ...省略... systemContainers := map[string]string{ statsapi.SystemContainerKubelet: nodeConfig.KubeletCgroupsName, statsapi.SystemContainerRuntime: nodeConfig.RuntimeCgroupsName, statsapi.SystemContainerMisc: nodeConfig.SystemCgroupsName, } for sys, name := range systemContainers { // skip if cgroup name is undefined (not all system containers are required) if name == "" { continue } s, _, err := sp.provider.GetCgroupStats(name) if err != nil { glog.Errorf("Failed to get system container stats for %q: %v", name, err) continue } // System containers don't have a filesystem associated with them. s.Logs, s.Rootfs = nil, nil s.Name = sys nodeStats.SystemContainers = append(nodeStats.SystemContainers, *s) } ...省略... }
通过阅读代码上下文,得知这里查找的是 --runtime-cgroups
和 --kubelet-cgroups
指定的cgroup。
之前调查的时候,网上有人说,将这两个参数的数值都设置为 /systemd/system.slice
, Github Issue #56850: Failed to get system container stats for.. :
--runtime-cgroups=/systemd/system.slice --kubelet-cgroups=/systemd/system.slice
对这个解决方法很怀疑,他设置的参数值明显和参数名称不搭,并且在我的环境中,这个方法无效,上面打印的日志就是这样设置以后打印的。
是不是 --runtime-cgroups
和 --kubelet-cgroups
应该设置为其它数值呢?
没找到具体的例子,从参数说明中也看不到要怎样设置,随便尝试了几种:
/ /sys/fs/cgroup/systemd/system.slice /system.slice/kubelet.service /sys/fs/cgroup/systemd/system.slice/kubelet.service
结果都不行,设置为哪个值,日志里就显示名称为哪个值的容器找不到。
继续调查
没办法,只能继续爬代码,具体过程就不说了,总之最后发现, sp.provider.GetCgroupStats(name)
是用cadvisor client从cadvisor中查找容器信息的。
cadvisor client的创建代码:
// cmd/kubelet/app/server.go: 418 func run(s *options.KubeletServer, kubeDeps *kubelet.Dependencies) (err error) { ... if kubeDeps.CAdvisorInterface == nil { imageFsInfoProvider := cadvisor.NewImageFsInfoProvider(s.ContainerRuntime, s.RemoteRuntimeEndpoint) kubeDeps.CAdvisorInterface, err = cadvisor.New(s.Address, uint(s.CAdvisorPort), imageFsInfoProvider, s.RootDirectory, cadvisor.UsingLegacyCadvisorStats(s.ContainerRuntime, s.RemoteRuntimeEndpoint)) if err != nil { return err } }
参照kubelet的做法,写一个从cadvisor中查询容器信息的小程序,看一下从cadvisor中到底能不能查找到目标容器:
// Copyright (C) 2019 lijiaocn <lijiaocn@foxmail.com> // // Distributed under terms of the GPL license. package main import ( "encoding/json" "flag" "fmt" "github.com/golang/glog" cadvisorapiv2 "github.com/google/cadvisor/info/v2" "k8s.io/kubernetes/pkg/kubelet/cadvisor" "time" ) type CmdLine struct { ContainerName string } var cmdline CmdLine func init() { flag.StringVar(&cmdline.ContainerName, "name", "/", "container name") } func main() { flag.Parse() ContainerRuntime := "docker" RemoteRuntimeEndpoint := "" imagefs := cadvisor.NewImageFsInfoProvider(ContainerRuntime, RemoteRuntimeEndpoint) usingLegacyStats := cadvisor.UsingLegacyCadvisorStats(ContainerRuntime, RemoteRuntimeEndpoint) ca, err := cadvisor.New("127.0.0.1", 4000, imagefs, "/var/lib/kubelet", usingLegacyStats) if err != nil { glog.Error(err) } if err := ca.Start(); err != nil { glog.Error(err) } options := cadvisorapiv2.RequestOptions{ IdType: cadvisorapiv2.TypeName, Count: 2, // 2 samples are needed to compute "instantaneous" CPU Recursive: true, //设置为true,递归查找,深入到目录中 } machineInfo, err := ca.MachineInfo() if err != nil { glog.Error(err.Error()) } bytes, err := json.Marshal(&machineInfo) fmt.Printf("machineInfo: %s\n", bytes) rootfsInfo, err := ca.RootFsInfo() if err != nil { glog.Error(err.Error()) } bytes, err = json.Marshal(&rootfsInfo) fmt.Printf("rootfsInfo: %s\n", bytes) infoMap, err := ca.ContainerInfoV2(cmdline.ContainerName, options) if err != nil { glog.Error(err.Error()) } if infoMap == nil { glog.Error("infoMap is null") } for name, value := range infoMap { fmt.Printf("%s: %s %s\n", name, value.Spec.Namespace, value.Spec.Image) } time.Sleep(600 * time.Second) }
上面的代码需要放到$GOPATH/src/k8s.io/kubernetes目录或者它的子目录中,例如放在新建的子目录中lijiaocn/cadvisor中:
$ ls $GOPATH/src/k8s.io/kubernetes/lijiaocn/cadvisor/main.go main.go $ cd $GOPATH/src/k8s.io/kubernetes/lijiaocn/cadvisor/ $ go build
编译得到文件cadvisor,将它拷贝到目标机器上,查看cadvisor发现的容器:
$ ./cadvisor kube-proxy /system.slice/rsyslog.service /system.slice/polkit.service /kubepods/besteffort/podca8a190e-156f-11e9-97b9-52540064c479/450f1b5757d45c2367fa06ec65de03508a47e9d9037cd5769a4c17e29299f10a /system.slice/kmod-static-nodes.service /system.slice/crond.service /system.slice/system-getty.slice /user.slice /system.slice/rhel-import-state.service /system.slice/systemd-udevd.service /kubepods /system.slice/system-selinux\x2dpolicy\x2dmigrate\x2dlocal\x2dchanges.slice /system.slice/kubelet.service ...省略... /systemd/system.slice ... /systemd/system.slice/docker.service ...
可以确定两件事情:第一,不需要在名称前面加上cgroup的挂载路径/sys/fs/cgroup;第二,传入的参数 /
、 /systemd/system.slice
以及 /system.slice/kubelet.service
等都是存在的。
直接用cadvisor能查到容器的cgroup,为什么kubelet无论如何也查不到呢?这里写的查询方法是直接抄的kubelet,为什么我们能查到,kubelet查不到?:
用./cadvisor能查到 /system.slice/kubelet.service
:
$ ./cadvisor --name=/system.slice/kubelet.service /system.slice/kubelet.service
陷入僵局。
继续调查
猛然想起还有另一个集群,在那个集群中似乎没有见过这个错误,两个集群使用的是同一个版本的kubelet。
比对两个集群的kubelet命令行参数,发现了不同:没有报该错误的集群上,没有使用 --docker-only
参数。
赶紧去看这个参数的作用:
--docker-only Only report docker containers in addition to root stats
莫非使用了该参数之后,cadvisor不采集 docker 以外的cgroup信息?
将这个参数去掉之后,错误消失!猜测大概是对的。
另外结合前面的分析过程,如果要设置–kubelet-cgroups和–runtime-cgroups,应该设置为如下的数值:
# 根据自己环境设置,我这里是CentOS7,用systemd启动kubelet和docker --kubelet-cgroups=/system.slice/kubelet.service --runtime-cgroups=/system.slice/docker.service
需要特别注意的是,这里的kubelet和docker,是在CentOS上用systemctl启动的,这两个cgroup都是systemd创建的。
如果不用systemctl启动,而是直接在命令行运行kubelet,例如:
./kubelet --kubelet-cgroups=/system.slice/kubelet.service --XXXX(省略)
会因为/system.slice/kubelet.service没有被创建,导致继续打印本页开头粘贴的错误日志,这时候才是真的找不到指定的cgroup。
参考
本文 原创首发 于网站:www.lijiaocn.com
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 调查:错误配置是容器面临的最高安全性问题
- Kubelet从1.7.16升级到1.9.11,Sandbox以外的容器都被重建的问题调查
- 罗永浩:Face ID 是弯路,锤子也在做智能音箱;国家药监局对长生生物的疫苗问题正式立案调查;阿里...
- Rust调查启示录
- 小程序开发工具调查
- 2019年数据泄露调查报告
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。