内容简介: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年数据泄露调查报告
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。