[英]How to check if a process is running inside docker container?
[Updated1] I have a shell which will change TCP kernel parameters in some functions, but now I need to make this shell run in Docker container, that means, the shell need to know it is running inside a container and stop configuring the kernel. [Updated1] I have a shell which will change TCP kernel parameters in some functions, but now I need to make this shell run in Docker container, that means, the shell need to know it is running inside a container and stop configuring the kernel.
Now I'm not sure how to achieve that, here is the contents of /proc/self/cgroup
inside the container:现在我不确定如何实现,这是容器内
/proc/self/cgroup
的内容:
9:hugetlb:/
8:perf_event:/
7:blkio:/
6:freezer:/
5:devices:/
4:memory:/
3:cpuacct:/
2:cpu:/docker/25ef774c390558ad8c4e9a8590b6a1956231aae404d6a7aba4dde320ff569b8b
1:cpuset:/
Any flags above can I use to figure out if this process is running inside a container?我可以使用上面的任何标志来确定此进程是否在容器内运行?
[Updated2]: I have also noticed Determining if a process runs inside lxc/Docker , but it seems not working in this case, the content in /proc/1/cgroup
of my container is: [Updated2]:我还注意到Determining if a process running inside lxc/Docker ,但在这种情况下似乎不起作用,我容器的
/proc/1/cgroup
中的内容是:
8:perf_event:/
7:blkio:/
6:freezer:/
5:devices:/
4:memory:/
3:cpuacct:/
2:cpu:/docker/25ef774c390558ad8c4e9a8590b6a1956231aae404d6a7aba4dde320ff569b8b
1:cpuset:/
No /lxc/containerid没有 /lxc/containerid
Docker creates .dockerenv
and
( removed in v1.11 ) files at the top of the container's directory tree so you might want to check if those exist. .dockerinit
Docker 在容器目录树的顶部创建
.dockerenv
和
(在 v1.11 中删除)文件,因此您可能需要检查它们是否存在。.dockerinit
Something like this should work.像这样的东西应该工作。
#!/bin/bash
if [ -f /.dockerenv ]; then
echo "I'm inside matrix ;(";
else
echo "I'm living in real world!";
fi
To check inside a Docker container if you are inside a Docker container or not can be done via /proc/1/cgroup
.要检查 Docker 容器内部是否在 Docker 容器中,可以通过
/proc/1/cgroup
完成。 As this post suggests you can to the following:正如这篇文章所建议的那样,您可以执行以下操作:
Outside a docker container all entries in /proc/1/cgroup
end on /
as you can see here:在 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:/
Inside a Docker container some of the control groups will belong to Docker (or LXC):在 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:/
We use the proc's sched (/proc/$PID/sched) to extract the PID of the process.我们使用 proc 的 sched (/proc/$PID/sched) 来提取进程的 PID。 The process's PID inside the container will differ then it's PID on the host (a non-container system).
容器内进程的 PID 与主机(非容器系统)上的 PID 不同。
For example, the output of /proc/1/sched on a container will return:例如,容器上 /proc/1/sched 的输出将返回:
root@33044d65037c:~# cat /proc/1/sched | head -n 1
bash (5276, #threads: 1)
While on a non-container host:在非容器主机上:
$ cat /proc/1/sched | head -n 1
init (1, #threads: 1)
This helps to differentiate if you are in a container or not.这有助于区分您是否在容器中。 eg you can do:
例如你可以这样做:
if [[ ! $(cat /proc/1/sched | head -n 1 | grep init) ]]; then {
echo in docker
} else {
echo not in docker
} fi
Thomas' solution as code:托马斯的解决方案作为代码:
running_in_docker() {
(awk -F/ '$2 == "docker"' /proc/self/cgroup | read non_empty_input)
}
Note笔记
The read
with a dummy variable is a simple idiom for Does this produce any output?使用虚拟变量
read
是一个简单的习惯用法,这会产生任何输出吗? . . It's a compact method for turning a possibly verbose
grep
or awk
into a test of a pattern.这是一种将可能冗长的
grep
或awk
转换为模式测试的紧凑方法。
For my money, I prefer to set an environment variable inside the docker image that can then be detected by the application.为了我的钱,我更喜欢在 docker 映像中设置一个环境变量,然后应用程序可以检测到该环境变量。
For example, this is the start of a demo Dockerfile
config:例如,这是演示
Dockerfile
配置的开始:
FROM node:12.20.1 as base
ENV DOCKER_RUNNING=true
RUN yarn install --production
RUN yarn build
The second line sets an envar called DOCKER_RUNNING
that is then easy to detect.第二行设置一个名为
DOCKER_RUNNING
的 envar,然后很容易检测到它。 The issue with this is that in a multi-stage build, you will have to repeat the ENV
line every time you FROM
off of an external image.这样做的问题是,在多阶段构建中,每次您从外部映像
FROM
时都必须重复ENV
行。 For example, you can see that I FROM
off of node:12.20.1
, which includes a lot of extra stuff (git, for example).例如,您可以看到 I
FROM
off of node:12.20.1
,其中包含很多额外的东西(例如 git)。 Later on in my Dockerfile
I then COPY
things over to a new image based on node:12.20.1-slim
, which is much smaller:稍后在我的
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"]
Even though this image target server
is in the same Dockerfile
, it requires the ENV var to be defined again because it has a different base image.即使此镜像目标
server
位于同一个Dockerfile
中,它也需要再次定义 ENV var,因为它具有不同的基础镜像。
If you make use of Docker-Compose, you could instead easily define an envar there.如果您使用 Docker-Compose,您可以轻松地在那里定义一个 envar。 For example, your
docker-compose.yml
file could look like this:例如,您
docker-compose.yml
文件可能如下所示:
version: "3.8"
services:
nodeserver:
image: michaeloryl/stackdemo
environment:
- NODE_ENV=production
- DOCKER_RUNNING=true
What works for me is to check for the inode number of the '/.'对我有用的是检查“/”的 inode 号。 Inside the docker, its a very high number.
在码头内部,这是一个非常高的数字。 Outside the docker, its a very low number like '2'.
在码头外,它是一个非常低的数字,例如“2”。 I reckon this approach would also depend on the FileSystem being used.
我认为这种方法还取决于所使用的文件系统。
Example例子
# ls -ali / | sed '2!d' |awk {'print $1'}
1565265
$ ls -ali / | sed '2!d' |awk {'print $1'}
2
In a script:在脚本中:
#!/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
golang code, via the /proc/%s/cgroup to check a process in a docker,include the k8s cluster golang 代码,通过 /proc/%s/cgroup 来检查 docker 中的进程,包括 k8s 集群
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
}
We needed to exclude processes running in containers, but instead of checking for just docker cgroups we decided to compare /proc/<pid>/ns/pid
to the init system at /proc/1/ns/pid
.我们需要排除在容器中运行的进程,但我们决定将
/proc/<pid>/ns/pid
与/proc/1/ns/pid
的 init 系统进行比较,而不是只检查 docker cgroups。 Example:例子:
pid=$(ps ax | grep "[r]edis-server \*:6379" | awk '{print $1}')
if [ $(readlink "/proc/$pid/ns/pid") == $(readlink /proc/1/ns/pid) ]; then
echo "pid $pid is the same namespace as init system"
else
echo "pid $pid is in a different namespace as init system"
fi
Or in our case we wanted a one liner that generates an error if the process is NOT in a container或者在我们的例子中,如果进程不在容器中,我们想要一个生成错误的衬垫
bash -c "test -h /proc/4129/ns/pid && test $(readlink /proc/4129/ns/pid) != $(readlink /proc/1/ns/pid)"
which we can execute from another process and if the exit code is zero then the specified PID is running in a different namespace.我们可以从另一个进程执行,如果退出代码为零,则指定的 PID 正在不同的命名空间中运行。
Based on Dan Walsh's comment about using SELinux ps -eZ | grep container_t
基于 Dan Walsh 关于使用 SELinux
ps -eZ | grep container_t
的评论| ps -eZ | grep container_t
, but without requiring ps
to be installed: ps -eZ | grep container_t
,但不需要安装ps
:
$ podman run --rm fedora:31 cat /proc/1/attr/current
system_u:system_r:container_t:s0:c56,c299
$ podman run --rm alpine cat /proc/1/attr/current
system_u:system_r:container_t:s0:c558,c813
$ docker run --rm fedora:31 cat /proc/1/attr/current
system_u:system_r:container_t:s0:c8,c583
$ cat /proc/1/attr/current
system_u:system_r:init_t:s0
This just tells you you're running in a container, but not which runtime.这只是告诉您您在容器中运行,而不是在哪个运行时。
Didn't check other container runtimes but https://opensource.com/article/18/2/understanding-selinux-labels-container-runtimes provides more info and suggests this is widely used, might also work for rkt and lxc?没有检查其他容器运行时,但https://opensource.com/article/18/2/understanding-selinux-labels-container-runtimes提供了更多信息并表明这被广泛使用,可能也适用于 rkt 和 lxc?
What works for me, as long as I know the system programs/scrips will be running on, is confirming if what's running with PID 1 is systemd
(or equivalent).只要我知道系统程序/脚本将在其上运行,对我有用的是确认使用PID 1运行的是否是
systemd
(或等效)。 If not, that's a container.如果不是,那是一个容器。 And this should be true for any linux container, not only docker.
这应该适用于任何 linux 容器,而不仅仅是 docker。
Had the need for this capability in 2022 on macOS and only the answer by @at0S still works from all the other options. 2022 年在 macOS 上需要此功能,只有@at0S 的答案仍然适用于所有其他选项。
/proc/1/cgroup
only has the root directory in a container unless configured otherwise /proc/1/cgroup
除非另有配置,否则只有容器中的根目录/proc/1/sched
showed the same in-container process number. /proc/1/sched
显示了相同的容器内进程号。 The name was different ( bash
) but that's not very portable.bash
),但这不是很便携。I did find an option not listed in the other answers: /proc/1/mounts
included an overlay
filesystem with "docker" in its path.我确实找到了其他答案中未列出的选项:
/proc/1/mounts
在其路径中包含了一个带有“docker”的overlay
文件系统。
[Updated1] I have a shell which will change TCP kernel parameters in some functions, but now I need to make this shell run in Docker container, that means, the shell need to know it is running inside a container and stop configuring the kernel. [Updated1]我有一个外壳,它将在某些功能中更改TCP内核参数,但是现在我需要使该外壳在Docker容器中运行,这意味着,该外壳需要知道它在容器内运行并停止配置内核。
Now I'm not sure how to achieve that, here is the contents of /proc/self/cgroup
inside the container:现在我不确定如何实现,这是容器内
/proc/self/cgroup
的内容:
9:hugetlb:/
8:perf_event:/
7:blkio:/
6:freezer:/
5:devices:/
4:memory:/
3:cpuacct:/
2:cpu:/docker/25ef774c390558ad8c4e9a8590b6a1956231aae404d6a7aba4dde320ff569b8b
1:cpuset:/
Any flags above can I use to figure out if this process is running inside a container?我可以使用上面的任何标志来确定此过程是否在容器内运行吗?
[Updated2]: I have also noticed Determining if a process runs inside lxc/Docker , but it seems not working in this case, the content in /proc/1/cgroup
of my container is: [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:/
No /lxc/containerid否/ lxc / containerid
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.