you are better than you think

备忘

last update:

现象描述

宿主机上创建容器时失败,kubelet log中可见报错信息mkdir /sys/fs/cgroup/memory/kubepods/burstable/pod79fe803c-072f-11e9-90ca-525400090c71/b98d4aea818bf9d1d1aa84079e1688cd9b4218e008c58a8ef6d6c3c106403e7b: no space left on devic

这个问题是kubernetes 1.9版本引入的,kubelet创建容器时EnableKernelMemoryAccounting导致的。kernel memory 在内核4.0以下的版本只是一个实验特性,存在使用后不能删除cgroup的问题,造成cgroup泄漏。

   Kernel memory support is a work in progress, and the current version provides basically functionality. (See Section 2.7)

关于这个问题的复现和分析,网络上有很多文章, 解决方案简单总结就是宿主机重启+关闭kmem accounting的kubelet。

kakuli同学这篇文章cgroup泄露问题对kubelet相关代码进行了详细的分析,并提供了1.12.4版本(我们的线上版本)的修复方案。 k8s社区在版本1.14,提供了开关可以关闭kmem accounting

同事有个模块会定期获取宿主机上的所有容器信息,代码中使用http client 请求docker engine获取容器信息。运行后收到用户反馈,程序导致系统fd泄漏,修复后代码如下,比原来代码多了一句 req.Close=true

    client := &http.Client{
        Timeout: time.Duration(timeout) * time.Millisecond,
        Transport: &http.Transport{
            Dial: unixDial,
        },
    }

    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        return nil, fmt.Errorf("NewRequest(): url = %s, err = %s", url, err)
    }

    req.Close = true // fd leak without setting this
    resp, err := client.Do(req)
    ...

因为我自己有个清理容器数据的代码也有类似逻辑。代码如下,但是这个清理容器的模块是运行一次就退出的(磁盘资源紧张时才运行) 所以没有这个问题。

  tr := &http.Transport{Dial: fakeDial, } 
    client := &http.Client{Transport: tr}
    resp, err := client.Get("http://localhost/containers/json")
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

翻了下源码发现这段注释

    // Close indicates whether to close the connection after
    // replying to this request (for servers) or after sending this
    // request and reading its response (for clients).
    //
    // For server requests, the HTTP server handles this automatically
    // and this field is not needed by Handlers.
    //
    // For client requests, setting this field prevents re-use of
    // TCP connections between requests to the same hosts, as if
    // Transport.DisableKeepAlives were set.
    Close bool

背景:登录到relay需要输入token+密码, 然后选择中控机。

需求:k8s机房大概有X个了,master ip 记不住,这次要给自动登录脚本加一个展示机器列表的功能,选择ip 或hostname 的序号进行登录,登录其他node机器时 只需要直接gg hostname 即可。 gg prod 会展示 master 列表,输入 master对应的序号,回车即可登录到master.

花时间学习了tcl的语法 完成了这个脚本。

先设置线上机器的ssh 会话复用 ,这样每天只需要输入一次token ,其他时间不需要再输入token了

host *
    Protocol 2
    ServerAliveInterval 30
    ServerAliveCountMax 3
host xxxx.xxx.efg
    ControlMaster auto
    ControlPath ~/.ssh/master-%r@%h
host xxx.xxx.abc
    ControlMaster auto
    ControlPath ~/.ssh/master-%r@%h