Shell 如何检查进程是否在docker容器内运行?

Shell 如何检查进程是否在docker容器内运行?,shell,docker,containers,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/25ef774c390558

[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]:我也注意到了,但在这种情况下似乎不起作用,我的容器的
/proc/1/cgroup
中的内容是:

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

否/lxc/containerid

通过
/proc/1/cgroup
可以在Docker容器内检查您是否在Docker容器内。正如建议的那样,您可以执行以下操作:

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


Thomas的解决方案作为代码:

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

带有虚拟变量的
读取
是一个简单的习惯用法,用于说明这是否会产生任何输出?。这是一种将可能冗长的
grep
awk
转换为模式测试的紧凑方法


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

这样的办法应该行得通

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

我们需要排除在容器中运行的进程,但我们决定将
/proc//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在另一个命名空间中运行。

我们使用进程的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

对我有效的方法是检查“/”的inode编号 在码头工人内部,这是一个非常高的数字。 在docker之外,这是一个非常低的数字,如“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
根据Dan Walsh关于使用SELinux
ps-eZ | grep container\u t
,但不要求安装
ps

$podman run--rm fedora:31 cat/proc/1/attr/current
系统:系统:集装箱:s0:c56,c299
$podman跑步——rm alpine cat/proc/1/attr/current
系统:系统:容器:s0:c558、c813
$docker run--rm fedora:31 cat/proc/1/attr/current
系统:系统:容器:s0:c8,c583
$cat/proc/1/attr/current
system\u:system\r:init\u t:s0
这只是告诉您正在容器中运行,而不是哪个运行时

没有检查其他容器运行时,但提供了更多信息,并建议广泛使用,可能也适用于rkt和lxc?

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
}
func GetContainerID(pid int32)字符串{
cgroup路径:=fmt.Sprintf(“/proc/%s/cgroup”,strconv.Itoa(int(pid)))
返回getContainerID(cgroupPath)
}
func GetImage(容器ID字符串)字符串{
如果containerId==“”{
返回“”
}
图像,确定:=集装箱图像[集装箱ID]
如果可以的话{
返回图像
}否则{
返回“”
}
}
func getContainerID(cgroupPath字符串)字符串{
集装箱ID:“”
content,err:=ioutil.ReadFile(cgroupPath)
如果错误!=零{
返回集装箱
}
行:=字符串。拆分(字符串(内容),“\n”)
对于u,行:=范围行{
字段:=字符串。拆分(行“:”)
如果len(字段)<3{
持续
}
cgroup_路径:=字段[2]
如果len(cgroup_路径)<64{
持续
}
//非系统码头工人
//5:网络优先级,网络cls:/docker/de630f22746b9c06c412858f26ca286c6cdfed086d3b302998aa403d9dcedc42
//3:net_cls:/kubepods/burstable/pod5f399c1a-f9fc-11e8-bf65-246e9659ebfc/9170559b8aadd07d99978d9460cf8d1c71552f3c64fefc7e9906ab3fb7e18f69
pos:=strings.LastIndex(cgroup_path,“/”)
如果位置>0{
id\u len:=len(cgroup\u路径)-pos-1
如果id_len==64{
//p、 InDocker=true
//码头工人id
containerID=cgroup_路径[pos+1:pos+1+64]
//调试(“docker id中的pid:%v”,pid,id)
返回集装箱
}
}
//系统化码头工人
//5:net_cls:/system.slice/docker-afd862d2ed48ef5dc0ce8f1863e4475894e331098c9a512789233ca9ca06fc62.scope
码头工人街:=“码头工人-
pos=strings.Index(cgroup\u路径,docker\u str)
如果位置>0{
pos_scope:=strings.Index(cgroup_路径,“.scope”)
id_len:=pos_scope-pos-len(docker_str)
如果pos\u scope>0&&id\u len==64{
containerID=cgroup\u path[pos+len(docker\u str):pos+len(docker\u str)+64]
返回集装箱
}
}
}
返回集装箱
}
使用环境变量 就我个人而言,我更喜欢在docker映像中设置一个环境变量,然后应用程序可以检测到该变量

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

FROM node:12.20.1 as base
ENV DOCKER_RUNNING=true
RUN yarn install --production
RUN yarn build
第二行设置了一个名为
DOCKER\u RUNNING
的envar,该envar很容易检测到。问题在于,在多阶段构建中,必须重复
ENV#!/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
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
}
FROM node:12.20.1 as base
ENV DOCKER_RUNNING=true
RUN yarn install --production
RUN yarn build
FROM node:12.20.1-slim as server
ENV DOCKER_RUNNING=true
EXPOSE 3000
COPY --from=base /build /build
CMD ["node", "server.js"]
version: "3.8"
services:
  nodeserver:
    image: michaeloryl/stackdemo
    environment:
      - NODE_ENV=production
      - DOCKER_RUNNING=true