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


当前回答

我们使用进程的调度(/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)

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

其他回答

最可靠的方法是检查/proc/1/cgroup.它会告诉你init进程的控制组,当你不在容器中时,它会是/ for所有层次结构。当您在容器内时,您将看到锚点的名称。对于LXC/Docker容器,它将分别类似于/ LXC/ <containerid>或/Docker /<containerid>。

有点跑题了,你可以用两种方法检查你是否在容器中:

Cat /proc/1/environ|tr "\0" "\n"|grep容器:如果你在容器中,你会看到容器变量。 Ps -ef | grep '\[':当你在容器中时,你将只看到grep进程,这意味着你看不到内核进程(例如[kthread])。注意:正常的macOS也不显示内核进程。

参考:这个Linux测试页面

在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

我们使用进程的调度(/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)

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

截至2022年,在lxd v4.0+中,到目前为止,没有一个答案可以同时适用于docker和lxc。

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

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

在所有主机系统中,PID 2是kthread:

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

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

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

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

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

所以像这样的东西似乎是有效的:

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