如何确定进程是否在lxc / Docker中运行?


172

有什么方法可以确定进程(脚本)是否在lxc容器(〜Docker运行时)中运行?我知道有些程序能够检测它们是否在虚拟机中运行,是否可以将类似的东西用于lxc / docker?


看起来似乎很老套,但最好改一下您的问题以描述您遇到的问题并询问如何解决它-否则,该问题被解决的可能性更高。在许多情况下,进行更改很困难,但如果您愿意的话,对您来说,简单地重新措辞并不难。
2013年

在容器内发出此命令时,会有一个有趣的响应:正常运行时间
Scott Stensland

Answers:


169

最可靠的方法是检查/proc/1/cgroup。它将告诉您初始化过程的控制组,并且当您不在容器中时,它将/用于所有层次结构。当您容器内时,将看到锚点的名称。使用LXC / Docker容器,将分别类似于/lxc/<containerid>/docker/<containerid>


13
码头工人现在使用docker而不是lxc在这些路径中使用
Andy

4
不适用于lxd / lxc容器,但是stackoverflow.com/a/20010626/170230可以。
Draco Ater

在更高版本的systemd中,您似乎不能依赖于/所有cgroup都使用process 1 。我的Debian 9的系统上(systemd 232)只有三个十cgroup中的(3:cpuset4:perf_event7:freezer)是在根; 其余的都在/init.scope。也就是说,我认为搜索该文件:/docker/可能是目前最可靠的启发式方法。
cjs

2
grep 'docker\|lxc' /proc/1/cgroup在Docker 18.09上为我工作。
rypel

1
不为我工作。使用LXC特权容器来托管Ubuntu 19.04,来宾Ubuntu 18.04。/ proc / 1 / cgroup不包含lxc字符串。
加布

157

Docker .dockerenv在容器内部目录树的根目录下创建一个文件。您可以运行此脚本进行验证

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


更多: Ubuntu实际上有一个bash脚本:/bin/running-in-container它实际上可以返回已被调用的容器的类型。可能会有帮助。虽然不了解其他主要发行版。


13
重要说明:该.dockerinit文件已在Docker的最新版本中删除,因此该方法不再起作用。在撰写本文时,该.dockerenv文件仍保留在原处,因此也许可以代替使用。
杰森R

在Debian /bin/running-in-container上由提供upstart。随着向systemd的过渡,它可能会消失。我希望不会-听起来很有用!
Max Murphy'9

“在目录树顶部”是什么意思?哪里是?
亚历山大·米尔斯

3
还有人指出,检查.dockerenv不推荐
戴夫

1
注意:仅当运行时是docker daemon时,对.dockerenv的测试才有效。如果您使用的是podman或其他功能,则此操作将失败。
本杰明·基彻

22

在新的ubuntu 16.04系统上,新的systemd&lxc 2.0

sudo grep -qa container=lxc /proc/1/environ

这对我适用于Ubuntu Focus 20.04。到目前为止,没有答案。
乔纳森·哈特利

16

在bash脚本中检查docker的一种简洁方法是:

#!/bin/bash
if grep docker /proc/1/cgroup -qa; then
   echo I'm running on docker.
fi

14

方便的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()

2
重要的提示!当容器在kubernetes中运行时,这似乎不起作用。相反,用“ kubepod”代替“ docker”代替最后一行。(或者,输入“或”语句检查两者;))
JJC

1
这是kubepods我猜。
rookie099

9

我们使用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的更多信息,请参见此处
BrianV

是的,但这不是初始化进程的名称,而是进程号。
MillerGeek's

这似乎仅适用于Docker。在LXC容器中,它将返回
Systemd

现在在docker中也返回1。它通常shinit存在,但是两者中几乎都可以。
Jan Hudec

bash-5.0# cat /proc/1/sched bash (1, #threads: 1)
docker

5

最简单的方法是检查环境。如果您具有container=lxc变量,则说明您位于容器中。

否则,如果您是root用户,则可以尝试执行mknodmount操作,如果失败,则很可能是您的容器中的功能已被丢弃。


这不仅适用于docker(我没有检查过),更重要的是适用于lxd / lxc容器(已检查),在这里/proc/1/cgroup您无法检测到。
Draco Ater

2
您可以用代码而不是伪代码来编辑答案吗?“ container = lxc”?不正确。你的意思是如果[[“” lxc“ =” $ container“]]吗?
亚历山大·米尔斯

3
我的意思是……这很奇怪,通常env变量都用大写字母,所以在这里要找些精度
Alexander Mills

7
docker run alpine env没有给出看起来像该变量的任何东西
Archimedes Trajano

3

我的答案仅适用于Node.js流程,但可能与某些偶然发现此问题以寻找Node.js特定答案的访客有关。

我遇到了同样的问题,并且仅出于此目的,/proc/self/cgroup我依靠创建了一个npm包来检测Node.js进程是否在Docker容器中运行。

集装箱NPM模块将帮助你在Node.js的 目前尚未在Io.js中对其进行测试,但在这里也可以正常工作。


感谢您使用此模块,似乎有几个待解决的开放修正-您仍在维护吗?
stevokk

2

检查以上所有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

在基于Mac的Docker容器上,这对我不起作用。返回空。Docker版本2.1.0.1(37199)。
splintercell

这个做了:def is_non_docker(): return os.path.exists('/proc/1/cgroup')按照这里公认的答案stackoverflow.com/questions/20010199/…–
splintercell

2
您会获得猫的无用使用奖。和无用的子流程之一。
Jan Hudec

是的,这是不必要的全新水平cat!好人:-D
Timmmm

您是对的,尽管它仍未囊括一切,但我将为它更新答案。@JanHudec
blakev

1

Docker每天都在发展,因此我们无法确定它们是否会.dockerenv .dockerinit在未来继续 发展。

在大多数Linux版本中,这init是第一个启动的过程。但是对于容器来说,这是不正确的。

#!/bin/bash
if ps -p1|grep -q init;then  
  echo "non-docker" 
else 
  echo "docker" 
fi

6
@RomanTrofimov LXC / Docker也没有。多么有趣的评论。
abourget

1
它在centos 7中也不起作用。当我在主机上运行时,它显示docker。看起来systemd正在以进程ID 1运行
Venkateswara Rao

@VenkateswaraRao-必须在容器内运行。目的是找出您是否在docker容器内。
Govind Kailas

1
@GovindKailas:问题是,这假设正常的PID是1 init,这在基于systemdlaunchd基于系统的系统上是不正确的
Gert van den Berg

3
@SamThomas:已启动,新贵,Solaris SMF,systemd,Sys V风格的init,BSD风格的init(这两个以及其他一些人可能将其PID称为1 init),OpenRC,initng,runit。看这里。大多数现代的基于Linux的系统都将使用systemd,有些则是较早的新贵...。所有现代的OS X系统都将使用launchd
Gert van den Berg,

0

这样的SO问答:“找出操作系统是否在虚拟环境中运行”;尽管与OP的问题不同,但确实确实回答了查找您所在容器的常见情况(如果有的话)。

特别是,安装并阅读此bash脚本的代码,该代码似乎运行良好:

什么 -

sudo apt install virt-what

virt-what在Ubuntu 16.04上不适用于1.14-1版本。需要补丁。
卢卡斯

0

我已经将JJC的答案翻译成红宝石

def in_docker
  File.open('/proc/1/cgroup', 'rt') do |f|
    contents = f.read
    return contents =~ /docker/i || contents =~ /kubepod/i
  end
rescue StandardError => e
  p 'Local development'
  p e
  false
end

-1

在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"
else 
  echo "Nay!! I'm not in a container"
fi

两者都返回1。
索林

-4

也许这可以解决问题:

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

那是你要的吗?希望对您有帮助=)


1
docker显然,容器内部没有二进制文件。
toriningen '18

3
嗯,这在控制容器具有docker并访问主机的Docker套接字的情况下(例如gitlab docker-in-docker)会失败。
shalomb

1
是的,您是对的,当然没有^^。当我阅读该问题时,对这个问题的理解是错误的。谢谢你,沙隆。
Leonardo Da Vinci
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.