有什么办法可以确定一个进程(脚本)是否在lxc容器(~Docker运行时)内运行?我知道有些程序能够检测它们是否在虚拟机内运行,那么lxc/docker是否有类似的功能?
如何确定一个进程是否在lxc/Docker内运行?
Docker在容器内的目录树根部创建一个
.dockerenv
文件。 这可以通过执行
ls -la /.dockerenv
来显示,它是在容器启动时创建的。
你可以运行这个脚本来验证。
#!/bin/bash
if [ -f /.dockerenv ]; then
echo "I'm inside matrix ;(";
echo "I'm living in real world!";
MORE:
Ubuntu实际上有一个bash脚本。/bin/running-in-container
,它可以返回它被调用的容器类型。可能会有帮助。
但不知道其他主要发行版的情况。
在 Debian 上,
/bin/running-in-container
是由
upstart
提供的。 随着向 systemd 的过渡,它可能会消失。 我希望不会--它听起来很有用!
Dave
:
还有人指出,检查
.dockerenv
是
not recommended
注意:对.dockerenv的测试只有在运行时是docker daemon时才有效。如果你使用的是podman或其他东西,则会失败。
现在是2020年8月,
/.dockerenv
在ubuntu:20.04和alpine:3.12上可用,所以我说这绝对是最佳答案。
Ubuntu 18.0.4没有
/bin/running-in-container
。
jpetazzo
发布于
2018-06-11
0
人赞同
最可靠的方法是检查
/proc/1/cgroup
。它将告诉你init进程的控制组,当你在
not
在一个容器中,这将是所有层次的
/
。当你在
inside
容器,你会看到锚点的名字。对于LXC/Docker容器,它将是类似
/lxc/<containerid>
或
/docker/<containerid>
的东西。
Andy
:
docker现在在这些路径中使用
docker
而不是
lxc
。
对lxd/lxc容器不起作用,但是
stackoverflow.com/a/20010626/170230
does.
rypel
:
grep 'docker\|lxc' /proc/1/cgroup
works for me on Docker 18.09.
Gab
:
对我来说不起作用。主机Ubuntu 19.04,客人Ubuntu 18.04,使用LXC特权容器。 /proc/1/cgroup不包含lxc字符串。
在我的docker镜像上:cat /proc/1/cgroup 0::/ 所以不起作用。
larss
发布于
2018-06-11
0
人赞同
On a new ubuntu 16.04 system, new systemd & lxc 2.0
sudo grep -qa container=lxc /proc/1/environ
这在Ubuntu focal 20.04上对我有效。这一点上面的答案都没有。
Alek
:
谢谢!这对lxc来说是有效的。你能解释一下为什么要用'-a'吗?难道
grep -q container=lxc /proc/1/environ
还不够吗?
/proc/$$/environ
separates environment variables with null bytes. Without
-a
, this passage from the man page applies: > By default, TYPE is binary, and grep suppresses output after null input binary data is discovered
fstamour
:
对我来说,使用podman,
/proc/1/environ
包含
container=podman
。所以我用
grep -qa '^container='
来代替。
oNaiPs
发布于
2018-06-11
0
人赞同
在bash脚本中检查docker/lxc的简明方法是。
#!/bin/bash
if grep -sq 'docker\|lxc' /proc/1/cgroup; then
echo "I am running on Docker."
JJC
发布于
2018-06-11
0
人赞同
便捷的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()
Founder
发布于
2018-06-11
0
人赞同
我们使用proc的sched(/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上工作。在LXC容器中,它返回Systemd PID 1
现在在docker中也是返回1。它通常是
sh
,而不是
init
,但在这两种情况下,它几乎可能是任何东西。
shalomb
:
在docker下,这种情况不再存在了 - 【替换代码0
creack
发布于
2018-06-11
0
人赞同
最简单的方法是检查环境。如果你有
container=lxc
变量,你就在一个容器内。
否则,如果你是root,你可以尝试执行
mknod
或
mount
操作,如果失败,你很可能是在一个有掉线功能的容器中。
这个不仅适用于docker(我没有检查过),更重要的是适用于lxd/lxc容器(检查过),其中
/proc/1/cgroup
不允许你检测。
你能用代码而不是伪代码来编辑答案吗?"container=lxc "并不恰当。你的意思是像if [["lxc" = "$container"]] ?
我的意思是......这很奇怪,通常环境变量都是大写的,所以我想在这里寻找一些精确性。
替换代码0】并没有给出类似于该变量的东西
mainmachine
发布于
2018-06-11
0
人赞同
这是一个老问题,但却是一个非常好的问题。)
我写了一些自动化脚本,我们在裸机、虚拟机和docker容器中运行,并根据脚本执行的平台进行逻辑分支。在我的案例中,我有创建容器和docker镜像的特权,所以这个解决方案只有在你控制整个堆栈的情况下才会有效。
Snippet of 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
为了保持简洁,我在上面的代码中省略了baremetal。
Ferry Boender
发布于
2018-06-11
0
人赞同
截至2022年,在lxd v4.0+的情况下,到目前为止没有一个答案对docker和lxc都有效。
A
.dockerenv
file doesn't work for non-docker containers.
Checking that all hierarchies in
/proc/1/cgroup
are
/
kinda maybe works. However, some hierarchies on non-containers are
/init.scope
(Ubuntu 20.04 cgroup 0 and 1). So 还有 not entirely reliable.
Checking for
container=lxc
in
/proc/1/environ
works for lxc but not docker. Also, it requires root rights.
到目前为止,我发现唯一的方法是在CentOS和Ubuntu上使用lxc(4.0)容器和Docker都能可靠地工作,并且
还有
doesn't require root rights, is to check PID 2.
在所有主机系统上,PID 2是
kthreadd
。
$ ps -p 2
PID TTY TIME CMD
2 ? 00:00:00 kthreadd
在容器中,这个PID要么不存在,要么不是kthreadd。docker和lxc都显示。
root@85396f8bce58:/# ps -p 2
PID TTY TIME CMD
root@85396f8bce58:/#
最好的方法似乎是检查/proc/2/status
。
$ head -n1 /proc/2/status
Name: kthreadd
So something like this seems to work:
if [ -n "$(grep 'kthreadd' /proc/2/status 2>/dev/null)" ]; then
echo "Not in container"
echo "In container";
在macOS上运行docker;通常没有pid 2。
With lxd 5.8, no process seen with pid 2
blakev
发布于
2018-06-11
0
人赞同
在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())
Proof of concept:
$ docker run --rm -it --mount type=bind,source=${PWD}/incontainer.py,target=/tmp/script.py python:3 python /tmp/script.py
这在基于Mac的docker容器上对我不起作用。结果是空的。Docker版本2.1.0.1(37199)。
这个人做到了。
def is_non_docker(): return os.path.exists('/proc/1/cgroup')
按照这里的公认答案
stackoverflow.com/questions/20010199/...
你获得了 "无用的猫奖"。还有一个 "无用使用子过程奖"。
Timmmm
:
是的,这是一个全新的水平的不必要的
cat
!好样的:-D
blakev
:
你是对的,我将更新它的答案,尽管它仍然不是包罗万象的。@JanHudec
Martin Tajur
发布于
2018-06-11
0
人赞同
我的答案只适用于
Node.js processes
但对于一些偶然发现这个问题并寻找Node.js具体答案的访问者来说,可能是相关的。
我也有同样的问题,并依靠
/proc/self/cgroup
。我创建了一个
npm包
只为了这个目的--检测一个Node.js进程是否在Docker容器中运行。
The
容器化的npm模块
将帮助你解决Node.js中的问题。它目前还没有在Io.js中测试,但也可能在那里工作。
kaiwan
发布于
2018-06-11
0
人赞同
This SO Q&A:
"找出操作系统是否在虚拟环境中运行"
;虽然与OP的问题不一样,但它确实回答了寻找你在哪个容器中的常见情况(如果有的话)。
特别是,安装并阅读这个bash脚本的代码,它似乎工作得相当好。
病毒什么的
:
sudo apt install virt-what
Lucas
:
在Ubuntu 16.04上无法使用
virt-what
1.14-1版本。需要补丁。
有趣的是,在windows的docker里面,
virt-what
报告了
hyperv
,就像我的WSL2 bash shell那样。
This does work in Ubuntu 20.04, it greps for "lxc" in /proc/1/environ
Souradeep Nanda
发布于
2018-06-11
0
人赞同
我已经把JJC的答案翻译成了ruby语言
def in_docker
File.open('/proc/1/cgroup', 'rt') do |f|
contents = f.read
return contents =~ /docker/i || contents =~ /kubepod/i
rescue StandardError => e
p 'Local development'
false
tantrix
发布于
2018-06-11
0
人赞同
这里有一个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
If you like tests with your code, 这里有一个Gist中的规格.
wcc526
发布于
2018-06-11
0
人赞同
golang代码得到pid container_id,你可以得到map container_id得到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
shalomb
发布于
2018-06-11
0
人赞同
在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"
echo "Nay!! I'm not in a container"
sorin
:
Returns 1 on both.
作品!谢谢!@sorin,实际上它只在主机级返回1,但在容器内返回0。
Govind Kailas
发布于
2018-06-11
0
人赞同
Docker每天都在发展,所以我们不能确定他们在未来是否会保留
.dockerenv .dockerinit
。
在大多数Linux系统中,
init
是第一个启动的进程。但在容器的情况下,这不是真的。
#!/bin/bash
if ps -p1|grep -q init;then
echo "non-docker"
echo "docker"
abourget
:
@RomanTrofimov LXC/Docker也没有。多么有趣的评论。
它在centos 7中也不工作。当我在主机上运行时,显示docker。看起来systemd是作为进程ID 1运行的。
@VenkateswaraRao - 这必须在容器内运行。其目的是找出你是否在一个docker容器内。
@GovindKailas:问题是,这假设正常的PID一是
init
,这在基于
systemd
或
launchd
的系统上是不成立的。
@SamThomas: launchd, upstart, Solaris SMF, systemd, Sys V style init, BSD style init (这两个和其他一些可能把他们的PID 1叫做
init
), OpenRC, initng, runit.
See here
.大多数基于Linux的现代系统会使用
systemd
,一些老的系统会使用upstart....。所有现代的OS X系统都会使用
launchd
。
Roeniss
发布于
2018-06-11
0
人赞同
有点跑题了,你可以看看
如果你在一个容器中或不在一个容器中
在两个方面。
cat /proc/1/environ|tr "\0" "\n"|grep container
:如果你在一个容器中,你会看到
container
变量。
ps -ef | grep '\['
:当你在一个容器中时,你会看到什么都没有,只有grep进程,这意味着没有你能看到的内核进程(例如:
[kthreadd]
)。注意:正常的macOS也不显示内核进程。
reference:
这个Linux测验页面
Leonardo Da Vinci
发布于
2018-06-11
0
人赞同
也许这能起到作用。
if [ -z $(docker ps -q) ]; then
echo "There is not process currently running"