如何确定某个进程是否在 lxc/Docker 内部运行?

2024-10-18 09:00:00
admin
原创
64
摘要:问题描述:有什么方法可以确定进程(脚本)是否在 lxc 容器(〜Docker 运行时)内运行?我知道有些程序能够检测它们是否在虚拟机内运行,lxc/docker 是否有类似的东西?解决方案 1:.dockerenvDocker在容器内的目录树根目录创建一个文件。执行以下命令可以看到ls -la /.docke...

问题描述:

有什么方法可以确定进程(脚本)是否在 lxc 容器(〜Docker 运行时)内运行?我知道有些程序能够检测它们是否在虚拟机内运行,lxc/docker 是否有类似的东西?


解决方案 1:

.dockerenvDocker在容器内的目录树根目录创建一个文件。执行以下命令可以看到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它可以返回它被调用的容器类型。可能会有帮助。不过不知道其他主要发行版的情况。

解决方案 2:

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

解决方案 3:

在新的 ubuntu 16.04 系统上,新的 systemd 和 lxc 2.0

sudo grep -qa container=lxc /proc/1/environ

解决方案 4:

在 Bash 脚本中检查 docker/lxc 的简洁方法是:

#!/bin/bash
if grep -sq 'docker|lxc' /proc/1/cgroup; then
   echo "I am running on Docker."
fi

解决方案 5:

方便的 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()

解决方案 6:

截至 2022 年,使用 lxd v4.0+,到目前为止,没有任何答案适用于 docker 和 lxc。

  • 文件.dockerenv不适用于非docker容器。

  • 检查所有层次结构/proc/1/cgroup是否都/有效也许可行。但是,非容器上的某些层次结构是有效的/init.scope(Ubuntu 20.04 cgroup 0 和 1)。因此也不完全可靠。

  • 检查 lxc 是否container=lxc工作/proc/1/environ,但 docker 不工作。此外,它需要 root 权限。

到目前为止我发现的唯一可以在 CentOS 和 Ubuntu 上使用 lxc(4.0)容器和 Docker 可靠运行并且不需要 root 权限的方法检查 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

因此这样的事情似乎有效:

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

解决方案 7:

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

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

解决方案 8:

最简单的方法是检查环境。如果你有变量container=lxc,则说明你位于容器内。

否则,如果您是root用户,您可以尝试执行mknodmount操作,如果失败,则您很可能处于具有丢失功能的容器中。

解决方案 9:

这是一个老问题,但确实是一个好问题。:)

我编写了一些自动化脚本,我们在裸机、虚拟机和 Docker 容器中运行这些脚本,并根据脚本在哪个平台上执行进行逻辑分支。就我而言,我有权创建容器和 Docker 映像,因此只有当您控制整个堆栈时,此解决方案才会起作用:

Dockerfile 片段:

FROM ubuntu:18.04

ENV PLATFORM="docker"

RUN apt update; \n...

$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

为了保持简洁,我在上面的代码中省略了裸机。

解决方案 10:

在 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('/.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

解决方案 11:

这个 SO Q&A:“查明操作系统是否在虚拟环境中运行”;虽然与 OP 的问题不一样,但它确实回答了查找您所在容器的常见情况(如果有的话)。

特别是,安装并阅读这个似乎运行良好的 bash 脚本的代码:

virt-什么

sudo apt install virt-what

解决方案 12:

在 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

解决方案 13:

我的答案仅适用于Node.js 流程,但对于偶然发现该问题并寻找 Node.js 特定答案的某些访问者来说可能具有相关性。

我遇到了同样的问题,并且依靠这个原因,/proc/self/cgroup我创建了一个npm 包,专门用于这个目的——检测 Node.js 进程是否在 Docker 容器内运行。

容器化的 npm 模块将在 Node.js 中为您提供帮助。它目前尚未在 Io.js 中测试,但可能也同样有效。

解决方案 14:

我已将 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

解决方案 15:

稍微偏离主题一点,您可以通过两种方式检查您是否在容器中:

  1. `cat /proc/1/environ|tr "" "
    "|grep container`container:如果您在容器中,您将看到变量。

  2. ps -ef | grep '[':当您在容器中时,您将看不到任何东西,只能看到 grep 进程,这意味着您看不到任何内核进程(例如[kthreadd])。注意:普通 macOS 也不会显示内核进程。

参考:这个 Linux 测验页面

解决方案 16:

这是 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

如果您喜欢对自己的代码进行测试,这里有一个要点规范。

解决方案 17:

golang代码获取pid container_id,可以获取map container_id获取docker镜像

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), "
")
    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
}

解决方案 18:

Docker 正在日新月异地发展,因此我们无法确定它们 .dockerenv .dockerinit将来是否会继续发展。

在大多数 Linux 版本中,init这是第一个启动的进程。但对于容器来说,情况并非如此。

#!/bin/bash
if ps -p1|grep -q init;then  
  echo "non-docker" 
else 
  echo "docker" 
fi

解决方案 19:

也许这个办法可行:

if [ -z $(docker ps -q) ]; then
    echo "There is not process currently running"
else
    echo "There are processes running"
fi

这就是你想要的吗?希望它能帮到你 =)

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用