有什么方法可以确定一个进程(脚本)是否在lxc容器中运行(~ Docker runtime)?我知道一些程序能够检测它们是否在虚拟机中运行,lxc/docker是否也有类似的功能?
最简单的方法是检查环境。如果你有container=lxc变量,你就在一个容器中。
否则,如果您是根用户,您可以尝试执行mknod或mount操作,如果失败,则很可能处于已删除功能的容器中。
最可靠的方法是检查/proc/1/cgroup.它会告诉你init进程的控制组,当你不在容器中时,它会是/ for所有层次结构。当您在容器内时,您将看到锚点的名称。对于LXC/Docker容器,它将分别类似于/ LXC/ <containerid>或/Docker /<containerid>。
Docker在容器内的目录树的根创建一个.dockerenv文件。这可以通过执行ls -la /命令来查看。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,它可以返回被调用的容器类型。可能会有帮助。 不过我不知道其他主要的发行版。
我的回答只适用于Node.js进程,但可能与一些无意中遇到这个问题并寻找Node.js特定答案的访问者相关。
我也遇到了同样的问题,我在/proc/self/cgroup上创建了一个npm包,专门用于检测一个Node.js进程是否在Docker容器中运行。
容器化的npm模块将在Node.js中帮助你。它目前还没有在Io.js中测试,但也可以在那里工作。
在新的ubuntu 16.04系统上,新的systemd和lxc 2.0
sudo grep -qa container=lxc /proc/1/environ
我们使用进程的调度(/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)
这有助于区分您是否在容器中。
Docker每天都在发展,所以我们不能肯定他们将来是否会保留.dockerenv .dockerinit。
在大多数Linux版本中,init是第一个启动的进程。但在容器的情况下,这不是真的。
#!/bin/bash
if ps -p1|grep -q init;then
echo "non-docker"
else
echo "docker"
fi
在bash脚本中检查docker/lxc的一个简单方法是:
#!/bin/bash
if grep -sq 'docker\|lxc' /proc/1/cgroup; then
echo "I am running on Docker."
fi
方便的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()
这个SO问答:“找出操作系统是否在虚拟环境中运行”;虽然与OP的问题不一样,但它确实回答了找到你所在容器的常见情况(如果有的话)。
特别是,安装并阅读这个bash脚本的代码,它似乎工作得很好:
virt-what:
sudo apt install virt-what
在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
也许这样做是有效果的:
if [ -z $(docker ps -q) ]; then
echo "There is not process currently running"
else
echo "There are processes running"
fi
这是你想要的吗?希望能有所帮助=)
在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
我已经将JJC的答案翻译成ruby
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
这是Ruby中的一个解决方案,
# Usage: DockerHelper.running_in_docker?
module DockerHelper
extend self
def running_in_docker?
!!(File.read("/proc/1/cgroup") =~ %r[^\d+:\w+:/docker/]) # !! => true/false
rescue Errno::ENOENT
false
end
end
如果您喜欢对代码进行测试,这里有一个要点说明。
这是一个老问题,但确实是个好问题。:)
我写了一些自动化脚本,我们在baremetal, VM和docker容器上运行,基于脚本执行的平台进行逻辑分支。在我的情况下,我有创建容器和docker镜像的特权,所以这个解决方案只在你控制整个堆栈时才会起作用:
Dockerfile片段:
FROM ubuntu:18.04
ENV PLATFORM="docker"
RUN apt update; \
...
然后,脚本可以在每个平台上检查$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
为了保持简洁,我在上面的代码中省略了裸金属。
golang代码得到pid container_id,你可以得到map container_id get docker image
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
}
截至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
有点跑题了,你可以用两种方法检查你是否在容器中:
Cat /proc/1/environ|tr "\0" "\n"|grep容器:如果你在容器中,你会看到容器变量。 Ps -ef | grep '\[':当你在容器中时,你将只看到grep进程,这意味着你看不到内核进程(例如[kthread])。注意:正常的macOS也不显示内核进程。
参考:这个Linux测试页面
推荐文章
- 如何检索给定相对的绝对路径
- 图形化对?
- 我如何能匹配一个字符串与正则表达式在Bash?
- 为什么cURL返回错误“(23)Failed writing body”?
- 在Unix shell中计算一列数字
- 在bash脚本中否定if条件
- 如何撤消“set -e”使bash立即退出,如果任何命令失败?
- 如何在docker映像的新容器中运行bash ?
- docker -撰写持久数据MySQL
- 管道命令输出到tee,但也保存退出代码的命令
- 如何自动添加用户帐户和密码与Bash脚本?
- 是否有方法按列“uniq”?
- 查找哪个进程被Linux OOM杀手杀死
- 如何在bash脚本中检查文件名的扩展名?
- 如何在Linux下将所有文件夹和文件重命名为小写?