相关文章推荐
淡定的充电器  ·  mysql ...·  2 周前    · 
坚韧的跑步鞋  ·  java word转html ...·  7 月前    · 

如何确定一个进程是否在lxc/Docker内运行?

236 人关注

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

2 个评论
mah
这可能看起来很迂腐,但最好重新表述你的问题,描述你遇到的问题,并询问如何解决它--如果不这样做,问题被关闭的可能性更大。在许多情况下,很难做出这种改变,但在你的问题中,如果你愿意,简单地重新措辞并不难。
在容器内发出这个命令时,有一个有趣的反应:uptime
linux
bash
docker
Mate Varga
Mate Varga
发布于 2013-11-16
19 个回答
at0S
at0S
发布于 2018-06-11
已采纳
0 人赞同

Docker在容器内的目录树根部创建一个 .dockerenv 文件。 这可以通过执行 ls -la /.dockerenv 来显示,它是在容器启动时创建的。

你可以运行这个脚本来验证。

#!/bin/bash
if [ -f /.dockerenv ]; then
    echo "I'm inside matrix ;(";
    echo "I'm living in real world!";

MORE: Ubuntu实际上有一个bash脚本。/bin/running-in-container,它可以返回它被调用的容器类型。可能会有帮助。 但不知道其他主要发行版的情况。

在 Debian 上, /bin/running-in-container 是由 upstart 提供的。 随着向 systemd 的过渡,它可能会消失。 我希望不会--它听起来很有用!
Dave
还有人指出,检查 .dockerenv not recommended
注意:对.dockerenv的测试只有在运行时是docker daemon时才有效。如果你使用的是podman或其他东西,则会失败。
现在是2020年8月, /.dockerenv 在ubuntu:20.04和alpine:3.12上可用,所以我说这绝对是最佳答案。
Ubuntu 18.0.4没有 /bin/running-in-container
jpetazzo
jpetazzo
发布于 2018-06-11
0 人赞同

最可靠的方法是检查 /proc/1/cgroup 。它将告诉你init进程的控制组,当你在 not 在一个容器中,这将是所有层次的 / 。当你在 inside 容器,你会看到锚点的名字。对于LXC/Docker容器,它将是类似 /lxc/<containerid> /docker/<containerid> 的东西。

Andy
docker现在在这些路径中使用 docker 而不是 lxc
对lxd/lxc容器不起作用,但是 stackoverflow.com/a/20010626/170230 does.
grep 'docker\|lxc' /proc/1/cgroup works for me on Docker 18.09.
Gab
对我来说不起作用。主机Ubuntu 19.04,客人Ubuntu 18.04,使用LXC特权容器。 /proc/1/cgroup不包含lxc字符串。
在我的docker镜像上:cat /proc/1/cgroup 0::/ 所以不起作用。
larss
larss
发布于 2018-06-11
0 人赞同

On a new ubuntu 16.04 system, new systemd & lxc 2.0

sudo grep -qa container=lxc /proc/1/environ
    
这在Ubuntu focal 20.04上对我有效。这一点上面的答案都没有。
Alek
谢谢!这对lxc来说是有效的。你能解释一下为什么要用'-a'吗?难道 grep -q container=lxc /proc/1/environ 还不够吗?
/proc/$$/environ separates environment variables with null bytes. Without -a , this passage from the man page applies: > By default, TYPE is binary, and grep suppresses output after null input binary data is discovered
对我来说,使用podman, /proc/1/environ 包含 container=podman 。所以我用 grep -qa '^container=' 来代替。
oNaiPs
oNaiPs
发布于 2018-06-11
0 人赞同

在bash脚本中检查docker/lxc的简明方法是。

#!/bin/bash
if grep -sq 'docker\|lxc' /proc/1/cgroup; then
   echo "I am running on Docker."
    
oNaiPs
谢谢 @DanielGriscom 这看起来好多了。
erik
当我的容器在kubernetes中运行时,这并不工作。
提醒一下,由于 "I'm "中的单引号,echo命令应该使用双引号。
JJC
JJC
发布于 2018-06-11
0 人赞同

便捷的Python函数可以检查是否在Docker中运行。

def in_docker():
    """ Returns: True if running in a Docker container, else False """
    with open('/proc/1/cgroup', 'rt') as ifh:
        return 'docker' in ifh.read()
    
JJC
重要提示!当容器在kubernetes中运行时,这似乎不起作用。相反,用 "kubepod "代替 "docker "来替换最后一行。 (或者,加入一个 "或 "的语句,对两者都进行检查;)
It's kubepods I guess.
Founder
Founder
发布于 2018-06-11
0 人赞同

我们使用proc的sched(/proc/$PID/sched)来提取进程的PID。进程在容器中的PID将与它在主机(非容器系统)上的PID不同。

例如,一个容器上的/proc/1/sched的输出结果 的输出将返回。

root@33044d65037c:~# cat /proc/1/sched | head -n 1
bash (5276, #threads: 1)

当在一个非容器主机上时。

$ cat /proc/1/sched  | head -n 1
init (1, #threads: 1)

这有助于区分你是否在一个容器中。

根据不同的操作系统,"init "可能需要用 "systemd "来代替。关于systemd的更多信息 here .
是的,但重点不是启动进程的名称,重点是进程编号。
这似乎只在Docker上工作。在LXC容器中,它返回Systemd PID 1
现在在docker中也是返回1。它通常是 sh ,而不是 init ,但在这两种情况下,它几乎可能是任何东西。
在docker下,这种情况不再存在了 - 【替换代码0
creack
creack
发布于 2018-06-11
0 人赞同

最简单的方法是检查环境。如果你有 container=lxc 变量,你就在一个容器内。

否则,如果你是root,你可以尝试执行 mknod mount 操作,如果失败,你很可能是在一个有掉线功能的容器中。

这个不仅适用于docker(我没有检查过),更重要的是适用于lxd/lxc容器(检查过),其中 /proc/1/cgroup 不允许你检测。
你能用代码而不是伪代码来编辑答案吗?"container=lxc "并不恰当。你的意思是像if [["lxc" = "$container"]] ?
我的意思是......这很奇怪,通常环境变量都是大写的,所以我想在这里寻找一些精确性。
替换代码0】并没有给出类似于该变量的东西
0 人赞同

这是一个老问题,但却是一个非常好的问题。)

我写了一些自动化脚本,我们在裸机、虚拟机和docker容器中运行,并根据脚本执行的平台进行逻辑分支。在我的案例中,我有创建容器和docker镜像的特权,所以这个解决方案只有在你控制整个堆栈的情况下才会有效。

Snippet of Dockerfile:

FROM ubuntu:18.04
ENV PLATFORM="docker"
RUN apt update; \

然后,脚本只需在每个平台上检查$PLATFORM的值,就可以得到想要的结果。

#!/bin/bash
# Check for executor specification in environment
case $PLATFORM in
  docker)
    # If running in Docker, do this stuff
    echo "Running containerized, proceeding..."
  virtual)
    # If running in a VM, do different stuff
    echo "Running on a VM, loading VM stuff..."
    modprobe some-kernel-module
    echo "Unknown executor specified! Exiting..."
    exit 1

为了保持简洁,我在上面的代码中省略了baremetal。

Ferry Boender
Ferry Boender
发布于 2018-06-11
0 人赞同

截至2022年,在lxd v4.0+的情况下,到目前为止没有一个答案对docker和lxc都有效。

  • A .dockerenv file doesn't work for non-docker containers.
  • Checking that all hierarchies in /proc/1/cgroup are / kinda maybe works. However, some hierarchies on non-containers are /init.scope (Ubuntu 20.04 cgroup 0 and 1). So 还有 not entirely reliable.
  • Checking for container=lxc in /proc/1/environ works for lxc but not docker. Also, it requires root rights.
  • 到目前为止,我发现唯一的方法是在CentOS和Ubuntu上使用lxc(4.0)容器和Docker都能可靠地工作,并且 还有 doesn't require root rights, is to check PID 2.

    在所有主机系统上,PID 2是 kthreadd

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

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

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

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

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

    So something like this seems to work:

    if [ -n "$(grep 'kthreadd' /proc/2/status 2>/dev/null)" ]; then
        echo "Not in container"
        echo "In container";
        
    在macOS上运行docker;通常没有pid 2。
    With lxd 5.8, no process seen with pid 2
    blakev
    blakev
    发布于 2018-06-11
    0 人赞同

    在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())
    

    Proof of concept:

    $ docker run --rm -it --mount type=bind,source=${PWD}/incontainer.py,target=/tmp/script.py python:3 python /tmp/script.py
        
    这在基于Mac的docker容器上对我不起作用。结果是空的。Docker版本2.1.0.1(37199)。
    这个人做到了。 def is_non_docker(): return os.path.exists('/proc/1/cgroup') 按照这里的公认答案 stackoverflow.com/questions/20010199/...
    你获得了 "无用的猫奖"。还有一个 "无用使用子过程奖"。
    是的,这是一个全新的水平的不必要的 cat !好样的:-D
    你是对的,我将更新它的答案,尽管它仍然不是包罗万象的。@JanHudec
    Martin Tajur
    Martin Tajur
    发布于 2018-06-11
    0 人赞同

    我的答案只适用于 Node.js processes 但对于一些偶然发现这个问题并寻找Node.js具体答案的访问者来说,可能是相关的。

    我也有同样的问题,并依靠 /proc/self/cgroup 。我创建了一个 npm包 只为了这个目的--检测一个Node.js进程是否在Docker容器中运行。

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

    谢谢你的这个模块,似乎有几个开放性的修正有待解决--你还在维护这个模块吗?
    Jeff
    这个模块已不再维护。此外,还需要一个能检测非Docker容器环境的Node.js模块。
    kaiwan
    kaiwan
    发布于 2018-06-11
    0 人赞同

    This SO Q&A: "找出操作系统是否在虚拟环境中运行" ;虽然与OP的问题不一样,但它确实回答了寻找你在哪个容器中的常见情况(如果有的话)。

    特别是,安装并阅读这个bash脚本的代码,它似乎工作得相当好。

    病毒什么的 :

    sudo apt install virt-what
        
    在Ubuntu 16.04上无法使用 virt-what 1.14-1版本。需要补丁。
    Peter V. Mørch
    有趣的是,在windows的docker里面, virt-what 报告了 hyperv ,就像我的WSL2 bash shell那样。
    This does work in Ubuntu 20.04, it greps for "lxc" in /proc/1/environ
    Souradeep Nanda
    Souradeep Nanda
    发布于 2018-06-11
    0 人赞同

    我已经把JJC的答案翻译成了ruby语言

    def in_docker
      File.open('/proc/1/cgroup', 'rt') do |f|
        contents = f.read
        return contents =~ /docker/i || contents =~ /kubepod/i
    rescue StandardError => e
      p 'Local development'
      false
        
    tantrix
    tantrix
    发布于 2018-06-11
    0 人赞同

    这里有一个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
    

    If you like tests with your code, 这里有一个Gist中的规格.

    wcc526
    wcc526
    发布于 2018-06-11
    0 人赞同

    golang代码得到pid container_id,你可以得到map container_id得到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
        
    shalomb
    shalomb
    发布于 2018-06-11
    0 人赞同

    在docker容器中,条目 /proc/self/cgroup 被挂载到主机上的cgroups。

    例如,在一个容器中

    # awk -F: '/cpuset/' /proc/self/cgroup
    3:cpuset:/docker/22bd0c154fb4e0d1b6c748faf1f1a12116acc21ce287618a115ad2bea41256b3
    

    而在主机上,同样的情况

    $ awk -F: '/cpuset/' /proc/self/cgroup
    3:cpuset:/
    

    使用外壳中的东西进行低调的测试

    is_running_in_container() {
      awk -F: '/cpuset/ && $3 ~ /^\/$/ { c=1 } END{ exit c }' /proc/self/cgroup
    if is_running_in_container; then
      echo "Aye!! I'm in a container"
      echo "Nay!! I'm not in a container"
        
    Returns 1 on both.
    作品!谢谢!@sorin,实际上它只在主机级返回1,但在容器内返回0。
    Govind Kailas
    Govind Kailas
    发布于 2018-06-11
    0 人赞同

    Docker每天都在发展,所以我们不能确定他们在未来是否会保留 .dockerenv .dockerinit

    在大多数Linux系统中, init 是第一个启动的进程。但在容器的情况下,这不是真的。

    #!/bin/bash
    if ps -p1|grep -q init;then  
      echo "non-docker" 
      echo "docker" 
        
    @RomanTrofimov LXC/Docker也没有。多么有趣的评论。
    Venkateswara Rao
    它在centos 7中也不工作。当我在主机上运行时,显示docker。看起来systemd是作为进程ID 1运行的。
    @VenkateswaraRao - 这必须在容器内运行。其目的是找出你是否在一个docker容器内。
    @GovindKailas:问题是,这假设正常的PID一是 init ,这在基于 systemd launchd 的系统上是不成立的。
    @SamThomas: launchd, upstart, Solaris SMF, systemd, Sys V style init, BSD style init (这两个和其他一些可能把他们的PID 1叫做 init ), OpenRC, initng, runit. See here .大多数基于Linux的现代系统会使用 systemd ,一些老的系统会使用upstart....。所有现代的OS X系统都会使用 launchd
    Roeniss
    Roeniss
    发布于 2018-06-11
    0 人赞同

    有点跑题了,你可以看看 如果你在一个容器中或不在一个容器中 在两个方面。

  • cat /proc/1/environ|tr "\0" "\n"|grep container :如果你在一个容器中,你会看到 container 变量。

  • ps -ef | grep '\[' :当你在一个容器中时,你会看到什么都没有,只有grep进程,这意味着没有你能看到的内核进程(例如: [kthreadd] )。注意:正常的macOS也不显示内核进程。

    reference: 这个Linux测验页面

  • Leonardo Da Vinci
    Leonardo Da Vinci
    发布于 2018-06-11
    0 人赞同

    也许这能起到作用。

    if [ -z $(docker ps -q) ]; then
        echo "There is not process currently running"