Contents

确定进程是否在容器内运行

1. 概述

有时,在运行脚本或程序时,我们需要知道我们是否在容器内运行它。这是因为有些命令与容器环境无关。例如,如果我们的脚本尝试使用sysctl 命令更改某些 OS 内核参数,那么它将无法在 docker 容器中运行。

在本文中,我们将讨论一些确定我们是否在 Linux 容器中的方法。

2. 使用控制组

我们可以从 init 进程的控制组中识别一个进程是在 docker 还是 LXC 容器中运行

$ docker run -it --rm --name myubuntu ubuntu:latest
itcodingman@blogdemo:/# cat /proc/1/cgroup
14:name=systemd:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5
13:rdma:/
12:pids:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5
11:hugetlb:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5
10:net_prio:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5
9:perf_event:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5
8:net_cls:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5
7:freezer:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5
6:devices:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5
5:memory:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5
4:blkio:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5
3:cpuacct:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5
2:cpu:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5
1:cpuset:/docker/184977d6a721a33b0df3855d197b222496d4d049ed118e3dc5e42ca3d22377b5

上面的命令显示 PID 为1的进程的控制组文件的内容。这是基于 Linux 的操作系统的初始化过程。如果某些行以*/docker/lxc开头*,则该进程正在 docker 或 LXC 容器内运行。如果进程在主机操作系统中运行,它们将仅以/开头。

控制组 是 Linux 内核功能,用于控制或跟踪一组进程的资源使用情况。在这里,我们所说的资源是指系统资源,如内存、CPU 和 IO 设备。Linux 将这些控制组表示为一个伪文件系统。Linux 容器共享其主机的内核。因此,Linux 在控制组中为它们使用单独的命名空间。

3. .dockerenv的存在

另一种流行的方法是检查.dockernev*文件在根位置*( / ) 的存在:

$ echo `[ ! -f /.dockerenv ]` $?

此命令检查文件是否存在,如果存在则打印1;否则,它会打印0。Docker 在创建根文件系统时创建此文件。LXC 驱动程序使用此文件以正确的方式设置环境变量。

但是,由于LXC 支持已经 从最近的 docker 版本中删除,这个文件将来可能不存在。

4. 使用 CPU 调度信息

**我们还可以查看init进程的调度 **信息,看看我们是否在容器内:

$ cat /proc/1/sched | head -n 1
bash (1, #threads: 1)

此命令提取具有 PID 1的进程的调度概览的第一行。对于 Linux 容器,它显示主进程的命令。对于 ubuntu 或 centos,它是bash

但是,如果进程不在容器中,则显示init——操作系统的初始化进程:

$ cat /proc/1/sched | head -n 1
init (1, #threads: 1)

在 CentOS 和 Debian 等一些 Linux 发行版中,初始化过程是systemd 。因此,对于他们来说,它显示的是system而不是init

5. 使用自定义环境变量

如果我们负责运行容器,有一种更简单有效的方法。**我们可以在运行 docker 容器时传递一个环境变量。**此变量将环境表示为容器环境:

$ docker run -it -d --name myubuntu -e OS_ENV=container ubuntu:latest
e4b26a308e0ab0ae6a976b7866004d9358920d195672f734701a02724494a8c6

在这里,我们使用*-e参数将环境变量OS_ENV作为容器*传递。现在,我们可以在容器中启动一个新的 bash shell,并通过变量识别环境:

$ docker exec -it myubuntu /bin/bash
itcodingman@blogdemo:/# echo $OS_ENV
container

对于主机操作系统,此值将不存在。因此,在任何程序或脚本中,我们都可以根据这个变量的存在来决定环境。