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

Mat*_*rga 152 linux bash docker

有没有办法确定进程(脚本)是否在lxc容器(~Docker运行时)内运行?我知道有些程序能够检测它们是否在虚拟机内运行,是否类似于lxc/docker?

jpe*_*zzo 154

最可靠的方法是检查/proc/1/cgroup.它将告诉您init进程的控制组,当您不在容器中时,它将/适用于所有层次结构.当您容器内时,您将看到锚点的名称; 其中,与LXC/Docker容器,将会像/lxc/<containerid>/docker/<containerid>分别.

  • docker现在在这些路径中使用`docker`而不是`lxc` (12认同)
  • 在我的 docker 映像上: cat /proc/1/cgroup 0::/ 所以不起作用。 (11认同)
  • 不适用于lxd/lxc容器,但http://stackoverflow.com/a/20010626/170230可以. (4认同)
  • 对于更高版本的 systemd,看起来您不能依赖对所有 cgroup 使用 `/` 的进程 1;在我的 Debian 9 系统 (systemd 232) 上,十个 cgroup 中只有三个(`3:cpuset`、`4:perf_event` 和 `7:freezer`)位于根目录;其余的都在`/init.scope`下。也就是说,我认为在该文件中搜索 `:/docker/` 可能是目前最可靠的启发式方法。 (3认同)
  • 不为我工作。使用 LXC 特权容器托管 Ubuntu 19.04,来宾 Ubuntu 18.04。/proc/1/cgroup 不包含 lxc 字符串。 (3认同)
  • grep'docker \ | lxc'/ proc / 1 / cgroup`在Docker 18.09上对我有效。 (2认同)
  • 结合两个答案以提高稳健性:`if [[ -f /.dockerenv ]] || grep -Eq '(lxc|docker)' /proc/1/cgroup; 然后回显 True;否则回显错误;fi`(虽然我不知道 cgroup 文件是否存在于每个 Linux 中;您可能需要添加额外的检查) (2认同)

at0*_*t0S 149

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

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


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

  • 重要提示:`.dockerinit`文件已在[最近版本的Docker中删除](https://github.com/docker/docker/issues/18355),因此此方法将不再起作用.在撰写本文时,`.dockerenv`文件仍然存在,所以也许可以使用它. (11认同)
  • 注意:仅当运行时是 docker 守护进程时,测试 .dockerenv 才有效。如果您使用 podman 或其他东西,则会失败。 (7认同)
  • 在 Debian 上,`/bin/running-in-container` 由 `upstart` 提供。随着过渡到 systemd,它可能会消失。我希望不会——听起来很有用! (4认同)
  • Ubuntu 18.0.4 没有“/bin/running-in-container”。 (3认同)
  • 其他人指出,检查`.dockerenv`是[不推荐](https://github.com/moby/moby/issues/18355#issuecomment-220484748) (2认同)
  • 现在是 2020 年 8 月,`/.dockerenv` 在 ubuntu:20.04 和 alpine:3.12 上可用,所以我想说这绝对是最好的答案 (2认同)

小智 19

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

sudo grep -qa container=lxc /proc/1/environ
Run Code Online (Sandbox Code Playgroud)

  • 这对我在 Ubuntu focus 20.04 上有效。上面的答案都没有做到这一点。 (2认同)

小智 15

在bash脚本中检查docker的简明方法是:

#!/bin/bash
if grep docker /proc/1/cgroup -qa; then
   echo I'm running on docker.
fi
Run Code Online (Sandbox Code Playgroud)


JJC*_*JJC 13

方便的Python函数来检查是否在Docker中运行(仅限linux,obvs.):

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()
Run Code Online (Sandbox Code Playgroud)

  • 重要的提示!当容器在 kubernetes 中运行时,这似乎不起作用。相反,用“kubepod”代替“docker”替换最后一行。(或者,放入一个“或”语句来检查两者;)) (4认同)
  • 我猜是“kubepods”。 (2认同)

Fer*_*der 12

截至 2022 年,对于 lxd v4.0+,迄今为止没有一个答案适用于 docker 和 lxc。

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

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

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

$ ps -p 2
  PID TTY          TIME CMD
    2 ?        00:00:00 kthreadd
Run Code Online (Sandbox Code Playgroud)

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

root@85396f8bce58:/# ps -p 2
    PID TTY          TIME CMD
root@85396f8bce58:/# 
Run Code Online (Sandbox Code Playgroud)

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

$ head -n1 /proc/2/status
Name:   kthreadd
Run Code Online (Sandbox Code Playgroud)

所以这样的事情似乎有效:

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

  • 在 macOS 上运行 docker;正常情况下没有pid 2。 (4认同)

小智 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)
Run Code Online (Sandbox Code Playgroud)

在非容器主机上:

$ cat /proc/1/sched  | head -n 1
init (1, #threads: 1)
Run Code Online (Sandbox Code Playgroud)

这有助于区分您是否在容器中.

  • 在docker下,情况不再是这样了 - ```bash-5.0# cat /proc/1/sched bash (1, #threads: 1)``` (4认同)
  • 现在 docker 中也返回 1。它通常是“sh”而不是“init”,但它几乎可以是任何一个。 (3认同)
  • 这似乎只适用于 Docker。在 LXC 容器中它返回 Systemd PID 1 (2认同)

cre*_*ack 7

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

否则,如果您是root用户,则可以尝试执行mknodmount操作,如果失败,您很可能在具有已删除功能的容器中.

  • `docker run alpine env` 没有给出任何看起来像那个变量的东西 (9认同)
  • 不适用于Docker.该变量未设置. (7认同)
  • 我的意思是......这很奇怪,通常env变量都是全部大写,所以在这里寻找一些精度 (3认同)
  • 你能用代码而不是伪代码编辑答案吗?"container = lxc"?是不合适的.你的意思是if [["lxc"="$ container"]]吗? (2认同)

小智 6

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

我编写了一些自动化脚本,我们在裸机、虚拟机和 Docker 容器中运行,并根据脚本执行的平台进行逻辑分支。就我而言,我有权创建容器和 docker 映像,因此只有当您控制整个堆栈时,此解决方案才有效:

Dockerfile 的片段:

FROM ubuntu:18.04

ENV PLATFORM="docker"

RUN apt update; \
...
Run Code Online (Sandbox Code Playgroud)

$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
    ;;
esac
Run Code Online (Sandbox Code Playgroud)

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


bla*_*kev 5

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

import os
import subprocess

def in_container():
    # type: () -> bool
    """ Determines if we're running in an lxc/docker container. """
    out = subprocess.check_output('cat /proc/1/sched', shell=True)
    out = out.decode('utf-8').lower()
    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', None) is not None
    ]
    return any(checks)
Run Code Online (Sandbox Code Playgroud)

  • 您将获得无用猫奖。子流程一的无用使用。 (2认同)