如何检查进程是否在docker容器中运行

har*_*ryz 65 shell containers docker

[Updated1]我有一个shell会在某些函数中更改TCP内核参数,但现在我需要让这个shell在Docker容器中运行,这意味着shell需要知道它在容器内运行并停止配置内核.

现在我不知道如何实现,这里是/proc/self/cgroup容器内部的内容:

9:hugetlb:/
8:perf_event:/
7:blkio:/
6:freezer:/
5:devices:/
4:memory:/
3:cpuacct:/
2:cpu:/docker/25ef774c390558ad8c4e9a8590b6a1956231aae404d6a7aba4dde320ff569b8b
1:cpuset:/
Run Code Online (Sandbox Code Playgroud)

我可以使用上面的任何标志来确定此进程是否在容器内运行?

[Updated2]:我还注意到确定进程是否在lxc/Docker中运行,但在这种情况下似乎不起作用/proc/1/cgroup,我的容器中的内容是:

8:perf_event:/
7:blkio:/
6:freezer:/
5:devices:/
4:memory:/
3:cpuacct:/
2:cpu:/docker/25ef774c390558ad8c4e9a8590b6a1956231aae404d6a7aba4dde320ff569b8b
1:cpuset:/
Run Code Online (Sandbox Code Playgroud)

没有/ lxc/containerid

at0*_*t0S 86

Docker 在容器的目录树顶部创建.dockerenv.dockerinit(在v1.11中删除)文件,因此您可能想要检查这些文件是否存在.

这样的事情应该有效.

#!/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)

  • 如果有其他人进入/然后他们是根,你遇到的问题比知道你是否在码头或者没有. (13认同)
  • 要注意长期依赖`/ .dockerenv`.它[不打算以这种方式使用](https://github.com/docker/docker/issues/18355#issuecomment-220484748). (8认同)
  • `.dockerinit`已在较新版本的Docker中删除. (4认同)
  • 当然,除非您或其他人在您的主机上创建了“/.dockerinit”(可能是偶然的),在这种情况下,在容器外部将会出错。 (3认同)
  • fwiw,Podman 不会创建 `/.dockerenv`。它确实创建了“/run/.containerenv”,但通过类似的逻辑,听起来像是不值得依赖的实现细节。请参阅 https://github.com/containers/libpod/issues/3586 了解一些特定于 podman 的替代方案。 (2认同)
  • @cowlinator Windows容器更简单,只需检查“HKLM\System\CurrentControlSet\Control\ContainerType”,任何值都意味着您位于Windows容器中。 (2认同)

Tho*_*rig 54

如果您在Docker容器内部,则要检查Docker容器内部是否可以通过/proc/1/cgroup.正如这篇文章建议你可以做到以下几点:

在docker容器之外的所有条目都在/proc/1/cgroup最后,/如下所示:

vagrant@ubuntu-13:~$ cat /proc/1/cgroup
11:name=systemd:/
10:hugetlb:/
9:perf_event:/
8:blkio:/
7:freezer:/
6:devices:/
5:memory:/
4:cpuacct:/
3:cpu:/
2:cpuset:/
Run Code Online (Sandbox Code Playgroud)

在Docker容器内部,一些控制组将属于Docker(或LXC):

vagrant@ubuntu-13:~$ docker run busybox cat /proc/1/cgroup
11:name=systemd:/
10:hugetlb:/
9:perf_event:/
8:blkio:/
7:freezer:/
6:devices:/docker/3601745b3bd54d9780436faa5f0e4f72bb46231663bb99a6bb892764917832c2
5:memory:/
4:cpuacct:/
3:cpu:/docker/3601745b3bd54d9780436faa5f0e4f72bb46231663bb99a6bb892764917832c2
2:cpuset:/
Run Code Online (Sandbox Code Playgroud)

  • `cat /proc/1/cgroup` 在 Docker 容器中仅输出 `0::/`。谁能告诉我发生了什么事吗? (6认同)
  • 这几乎只适用于 Linux,不适用于 Darwin 或其他甚至不使用 procfs 的 BSD。 (4认同)
  • "在一个docker容器外面,/ proc/1/cgroup中的所有条目都以/结尾"并不严格.以ubuntu 16.04为例,我有:`12:perf_event:/ 11:blkio:/init.scope 10:cpuset:/ 9:devices:/init.scope 8:hugetlb:/ 7:cpu,cpuacct:/init.scope 6:net_cls,net_prio:/ 5:内存:/init.scope 4:pids:/init.scope 3:rdma:/ 2:freezer:/ 1:name = systemd:/init.scope` (2认同)
  • @Christian Docker/LXC 是 Linux 独有的东西,所以没关系,对吧:)? (2认同)

小智 21

我们使用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)

这有助于区分您是否在容器中.你可以这样做:

if [[ ! $(cat /proc/1/sched | head -n 1 | grep init) ]]; then {
    echo in docker
} else {
    echo not in docker
} fi
Run Code Online (Sandbox Code Playgroud)

  • 根据操作系统的不同,可能需要将“ init”替换为“ systemd”。有关systemd的更多信息,请点击此处(https://www.tecmint.com/systemd-replaces-init-in-linux/)。 (2认同)
  • 如@BrianV所述,这对我也不起作用。 (2认同)
  • 在运行在k8s集群上的Docker容器中,`head -n1 / proc / 1 / sched`返回`dumb-init(1,#threads:1)`,因此此答案中建议的检查失败。(此外,与答案所暗示的相反,尽管我在容器中执行此操作,但PID在该行中显示为“ 1”。) (2认同)

Hen*_*eld 17

托马斯的代码解决方案:

running_in_docker() {
  (awk -F/ '$2 == "docker"' /proc/self/cgroup | read non_empty_input)
}
Run Code Online (Sandbox Code Playgroud)

注意

read与一个虚拟变量是一个简单的成语,这是否产生任何输出?.它是一种紧凑的方法,用于转换可能冗长grep或模式awk测试.

关于阅读的补充说明

  • 除了......这在一些环境中会失败,因为,例如,`3:cpu,cpuacct:/ system.slice/docker-1ce79a0dec4a2084d54acf187a1e177e0339dc90d0218b48b4456576ecaf291e.scope`将不匹配.更简单的`grep -q docker/proc/1/cgroup`; 那个结果代码也应该足够了. (6认同)
  • `read`可能适用于`bash`,但在最常用的`dash` shell中你必须使用`read dummy`(或类似的)或者使用类似`[-n"$(command)"]的结构. (2认同)

小智 8

对我有用的是检查“/”的 inode 编号。在 docker 内部,这是一个非常高的数字。在码头外,它是一个非常低的数字,如“2”。我认为这种方法也取决于所使用的文件系统。

例子

码头工人内部:

# ls -ali / | sed '2!d' |awk {'print $1'}
1565265
Run Code Online (Sandbox Code Playgroud)

码头外

$ ls -ali / | sed '2!d' |awk {'print $1'}
2
Run Code Online (Sandbox Code Playgroud)

在脚本中:

#!/bin/bash
INODE_NUM=`ls -ali / | sed '2!d' |awk {'print $1'}`
if [ $INODE_NUM == '2' ];
then
        echo "Outside the docker"
else
        echo "Inside the docker"
fi
Run Code Online (Sandbox Code Playgroud)

  • 与 `ls -di /` 相同?似乎 inode num 在不同平台上不可靠 (2认同)
  • `stat -c %i` 比 `ls -ali / | 更简单 sed '2!d' |awk {'打印 $1'}` (2认同)

Mic*_*ryl 5

使用环境变量

为了我的钱,我更喜欢在 docker 镜像中设置一个环境变量,然后应用程序可以检测到它。

例如,这是演示Dockerfile配置的开始:

FROM node:12.20.1 as base
ENV DOCKER_RUNNING=true
RUN yarn install --production
RUN yarn build
Run Code Online (Sandbox Code Playgroud)

第二行设置了一个名为的 envar DOCKER_RUNNING,然后很容易检测到。问题在于,在多阶段构建中,ENV每次FROM离开外部图像时都必须重复该行。例如,您可以看到 I FROMoff of node:12.20.1,其中包含许多额外的内容(例如 git)。后来在我的Dockerfile我然后COPY事情转移到一个基于 的新图像node:12.20.1-slim,它要小得多:

FROM node:12.20.1-slim as server
ENV DOCKER_RUNNING=true
EXPOSE 3000
COPY --from=base /build /build
CMD ["node", "server.js"]
Run Code Online (Sandbox Code Playgroud)

即使这个图像目标server在同一个 中Dockerfile,它也需要重新定义 ENV 变量,因为它有一个不同的基础图像。

如果您使用 Docker-Compose,您可以轻松地在那里定义一个 envar。例如,您的docker-compose.yml文件可能如下所示:

version: "3.8"
services:
  nodeserver:
    image: michaeloryl/stackdemo
    environment:
      - NODE_ENV=production
      - DOCKER_RUNNING=true
Run Code Online (Sandbox Code Playgroud)

  • 这太好了,只是明确 (2认同)