有什么方法可以确定一个进程(脚本)是否在lxc容器中运行(~ Docker runtime)?我知道一些程序能够检测它们是否在虚拟机中运行,lxc/docker是否也有类似的功能?


当前回答

这是Ruby中的一个解决方案,

# Usage: DockerHelper.running_in_docker?
module DockerHelper
  extend self

  def running_in_docker?
    !!(File.read("/proc/1/cgroup") =~ %r[^\d+:\w+:/docker/]) # !! => true/false
  rescue Errno::ENOENT
    false
  end
end

如果您喜欢对代码进行测试,这里有一个要点说明。

其他回答

在bash脚本中检查docker/lxc的一个简单方法是:

#!/bin/bash
if grep -sq 'docker\|lxc' /proc/1/cgroup; then
   echo "I am running on Docker."
fi

截至2022年,在lxd v4.0+中,到目前为止,没有一个答案可以同时适用于docker和lxc。

dockerenv文件不适用于非docker容器。 检查/proc/1/cgroup中的所有层次结构都是/有点可能工作。然而,非容器上的一些层次结构是/init。scope (Ubuntu 20.04 cgroup 0和1).所以也不完全可靠。 在/proc/1/environ中检查container=lxc适用于lxc,但不适用于docker。此外,它还需要根权限。

到目前为止,我发现唯一一种在CentOS和Ubuntu上使用lxc(4.0)容器和Docker可靠工作的方法,而且不需要root权限,就是检查PID 2。

在所有主机系统中,PID 2是kthread:

$ ps -p 2
  PID TTY          TIME CMD
    2 ?        00:00:00 kthreadd

在容器中,这个PID要么不存在,要么不是kthread。docker和lxc都显示:

root@85396f8bce58:/# ps -p 2
    PID TTY          TIME CMD
root@85396f8bce58:/# 

最好的方法似乎是检查/proc/2/status:

$ head -n1 /proc/2/status
Name:   kthreadd

所以像这样的东西似乎是有效的:

if [ -n "$(grep 'kthreadd' /proc/2/status 2>/dev/null)" ]; then
    echo "Not in container"
else
    echo "In container";
fi

我的回答只适用于Node.js进程,但可能与一些无意中遇到这个问题并寻找Node.js特定答案的访问者相关。

我也遇到了同样的问题,我在/proc/self/cgroup上创建了一个npm包,专门用于检测一个Node.js进程是否在Docker容器中运行。

容器化的npm模块将在Node.js中帮助你。它目前还没有在Io.js中测试,但也可以在那里工作。

golang代码得到pid container_id,你可以得到map container_id get docker image

func GetContainerID(pid int32) string {
    cgroupPath := fmt.Sprintf("/proc/%s/cgroup", strconv.Itoa(int(pid)))
    return getContainerID(cgroupPath)
}

func GetImage(containerId string) string {
    if containerId == "" {
        return ""
    }
    image, ok := containerImage[containerId]
    if ok {
        return image
    } else {
        return ""
    }
}
func getContainerID(cgroupPath string) string {
    containerID := ""
    content, err := ioutil.ReadFile(cgroupPath)
    if err != nil {
        return containerID
    }
    lines := strings.Split(string(content), "\n")
    for _, line := range lines {
        field := strings.Split(line, ":")
        if len(field) < 3 {
            continue
        }
        cgroup_path := field[2]
        if len(cgroup_path) < 64 {
            continue
        }
        // Non-systemd Docker
        //5:net_prio,net_cls:/docker/de630f22746b9c06c412858f26ca286c6cdfed086d3b302998aa403d9dcedc42
        //3:net_cls:/kubepods/burstable/pod5f399c1a-f9fc-11e8-bf65-246e9659ebfc/9170559b8aadd07d99978d9460cf8d1c71552f3c64fefc7e9906ab3fb7e18f69
        pos := strings.LastIndex(cgroup_path, "/")
        if pos > 0 {
            id_len := len(cgroup_path) - pos - 1
            if id_len == 64 {
                //p.InDocker = true
                // docker id
                containerID = cgroup_path[pos+1 : pos+1+64]
                // logs.Debug("pid:%v in docker id:%v", pid, id)
                return containerID
            }
        }
        // systemd Docker
        //5:net_cls:/system.slice/docker-afd862d2ed48ef5dc0ce8f1863e4475894e331098c9a512789233ca9ca06fc62.scope
        docker_str := "docker-"
        pos = strings.Index(cgroup_path, docker_str)
        if pos > 0 {
            pos_scope := strings.Index(cgroup_path, ".scope")
            id_len := pos_scope - pos - len(docker_str)
            if pos_scope > 0 && id_len == 64 {
                containerID = cgroup_path[pos+len(docker_str) : pos+len(docker_str)+64]
                return containerID
            }
        }
    }
    return containerID
}

在Python中检查以上所有的解决方案:

import os

def in_container():
    proc_1 = r'/proc/1/sched'

    if os.path.exists(proc_1):
        with open(proc_1, 'r') as fp:
            out = fp.read()
    else:
        out = ''

    checks = [
        'docker' in out,
        '/lxc/' in out,
        out.split(' ')[0] not in ('systemd', 'init',),
        os.path.exists('./dockerenv'),
        os.path.exists('/.dockerinit'),
        os.getenv('container') is not None
    ]
    return any(checks)


if __name__ == '__main__':
    print(in_container())

概念证明:

$ docker run --rm -it --mount type=bind,source=${PWD}/incontainer.py,target=/tmp/script.py python:3 python /tmp/script.py
True