Kubernetes问题调查:failed to get cgroup stats for /systemd/system.slice

栏目: 编程工具 · 发布时间: 5年前

内容简介: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.sliceGithub 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。

参考

  1. 《cgroup:linux的cgroup的使用》
  2. Github Issue #56850: Failed to get system container stats for..

Kubernetes问题调查:failed to get cgroup stats for /systemd/system.slice

本文 原创首发 于网站:www.lijiaocn.com


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

平台战略

平台战略

陈威如、余卓轩 / 中信出版社 / 2013-1 / 58.00元

《平台战略:正在席卷全球的商业模式革命》内容简介:平台商业模式的精髓,在于打造一个完善的、成长潜能强大的“生态圈”。它拥有独树一帜的精密规范和机制系统,能有效激励多方群体之间互动,达成平台企业的愿景。纵观全球许多重新定义产业架构的企业,我们往往就会发现它们成功的关键——建立起良好的“平台生态圈”,连接两个以上群体,弯曲、打碎了既有的产业链。 平台生态圈里的一方群体,一旦因为需求增加而壮大,另......一起来看看 《平台战略》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具