如何检查进程是否在docker容器中运行

时间:2014-05-07 08:49:23

标签: shell docker containers

[Updated1]我有一个shell会在某些函数中更改TCP内核参数,但现在我需要让这个shell在Docker容器中运行,这意味着shell需要知道它在容器内运行并停止配置内核。

现在我不知道如何实现这一点,这里是容器内/proc/self/cgroup的内容:

9:hugetlb:/
8:perf_event:/
7:blkio:/
6:freezer:/
5:devices:/
4:memory:/
3:cpuacct:/
2:cpu:/docker/25ef774c390558ad8c4e9a8590b6a1956231aae404d6a7aba4dde320ff569b8b
1:cpuset:/

我可以使用上面的任何标志来确定此进程是否在容器内运行?

[Updated2]:我也注意到Determining if a process runs 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:/

否/ lxc / containerid

10 个答案:

答案 0 :(得分:73)

Docker在容器的目录树顶部创建.dockerenv .dockerinit removed in v1.11)文件,因此您可能需要检查是否那些存在。

这样的事情应该有效。

#!/bin/bash
if [ -f /.dockerenv ]; then
    echo "I'm inside matrix ;(";
else
    echo "I'm living in real world!";
fi

答案 1 :(得分:47)

如果您位于Docker容器内,则要检查Docker容器内部是否可以通过/proc/1/cgroup完成。正如this post建议您可以执行以下操作:

在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:/

在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:/

答案 2 :(得分:19)

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

这有助于区分您是否在容器中。例如,你可以这样做:

if [[ ! $(cat /proc/1/sched | head -n 1 | grep init) ]]; then {
    echo in docker
} else {
    echo not in docker
} fi

答案 3 :(得分:14)

托马斯的解决方案代码:

running_in_docker() {
  (awk -F/ '$2 == "docker"' /proc/self/cgroup | read non_empty_input)
}

请注意

带有虚拟变量的read的一个简单的习惯用法吗?这会产生任何输出吗?。这是一种将可能冗长的grepawk转换为模式的测试的紧凑方法。

Additional note on read

答案 4 :(得分:4)

使用环境变量

为了我的钱,我更喜欢在 docker 镜像中设置一个环境变量,然后应用程序可以检测到该变量。

例如,这是演示 Dockerfile 配置的开始:

FROM node:12.20.1 as base
ENV DOCKER_RUNNING=true
RUN yarn install --production
RUN yarn build

第二行设置了一个名为 DOCKER_RUNNING 的环境,然后很容易检测到。这样做的问题是,在多阶段构建中,您每次 ENV 关闭外部映像时都必须重复 FROM 行。例如,您可以看到 I FROM off of node:12.20.1,其中包含许多额外的内容(例如 git)。稍后在我的 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"]

即使此图像目标 server 在同一个 Dockerfile 中,它也需要再次定义 ENV 变量,因为它具有不同的基础图像。

如果您使用 Docker-Compose,您可以轻松地在那里定义一个 envar。例如,您的 docker-compose.yml 文件可能如下所示:

version: "3.8"
services:
  nodeserver:
    image: michaeloryl/stackdemo
    environment:
      - NODE_ENV=production
      - DOCKER_RUNNING=true

答案 5 :(得分:1)

我们需要排除在容器中运行的进程,但是我们决定将/proc/<pid>/ns/pid/proc/1/ns/pid处的init系统进行比较,而不是只检查docker cgroup。例如:

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

或者在我们的情况下,如果流程不在容器中,我们需要一个生成错误的衬管

bash -c "test -h /proc/4129/ns/pid && test $(readlink /proc/4129/ns/pid) != $(readlink /proc/1/ns/pid)"

我们可以从另一个进程执行,如果退出代码为零,则指定的PID在不同的命名空间中运行。

答案 6 :(得分:1)

对我有用的是检查'/'的索引节点号。 在docker内部,其数量非常高。 在docker外部,其数字非常低,例如“ 2”。 我认为这种方法还取决于所使用的FileSystem。

示例

在docker内部:

# ls -ali / | sed '2!d' |awk {'print $1'}
1565265

在码头工人外部

$ ls -ali / | sed '2!d' |awk {'print $1'}
2

在脚本中:

#!/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

答案 7 :(得分:0)

我创建了一个小的python脚本。希望有人发现它有用。 : - )

#!/usr/bin/env python3
#@author Jorge III Altamirano Astorga 2018
import re
import math

total = None
meminfo = open('/proc/meminfo', 'r')
for line in meminfo:
    line = line.strip()
    if "MemTotal:" in line:
        line = re.sub("[^0-9]*", "", line)
        total = int(line)
meminfo.close()
print("Total memory: %d kB"%total)

procinfo = open('/proc/self/cgroup', 'r')
for line in procinfo: 
    line = line.strip()
    if re.match('.{1,5}:name=systemd:', line):
        dockerd = "/sys/fs/cgroup/memory" + \
            re.sub("^.{1,5}:name=systemd:", "", line) + \
            "/memory.stat"
        #print(dockerd)
        memstat = open(dockerd, 'r')
        for memline in memstat:
            memline = memline.strip()
            if re.match("hierarchical_memory_limit", memline):
                memline = re.sub("[^0-9]*", \
                    "", memline)  
                total = math.floor(int(memline) / 2**10)
        memstat.close()
procinfo.close()
print("Total available memory to the container: %d kB"%total)

答案 8 :(得分:0)

基于Dan Walsh的comment关于使用SELinux if(GetKeyboardState(NULL)==TRUE){ reload = TRUE; if(GetKeyState(VK_UP)<0){ fb--; } if(GetKeyState(VK_DOWN)<0){ fb++; } if(GetKeyState(VK_RIGHT)<0){ lr--; } if(GetKeyState(VK_LEFT)<0){ lr++; } if(GetKeyState(0x57)<0){ p++; } if(GetKeyState(0x53)<0){ p--; } } break; } } break; 的知识,但不需要安装ps -eZ | grep container_t

ps

这只是告诉您您正在 a 容器中运行,而不是哪个运行时。

没有检查其他容器的运行时,但是https://opensource.com/article/18/2/understanding-selinux-labels-container-runtimes提供了更多信息并暗示了它的广泛使用,可能也可以用于rkt和lxc?

答案 9 :(得分:0)

golang代码

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
}