如何从容器本身获取 Docker Linux 容器信息?

Posted

技术标签:

【中文标题】如何从容器本身获取 Docker Linux 容器信息?【英文标题】:How can I get Docker Linux container information from within the container itself? 【发布时间】:2014-01-26 12:51:38 【问题描述】:

我想让我的docker containers 了解他们的配置,就像您可以通过元数据获取有关 EC2 实例的信息一样。

我可以使用(前提是docker 正在侦听端口4243

curl http://172.17.42.1:4243/containers/$HOSTNAME/json

获取它的一些数据,但想知道是否有更好的方法至少获取容器的完整 ID,因为HOSTNAME 实际上缩短为 12 个字符,而 docker 似乎执行“最佳匹配”就可以了。

另外,如何获取 docker 主机的外部 IP(除了访问 AWS 特有的 EC2 元数据)

【问题讨论】:

注意:在尝试以下任何尝试在容器内使用 /var/run/docker.sock 的方法之前,您应该阅读此lvh.io/posts/… 如果@harschware 的链接断开,我将在这里总结一下:通过授予容器对/var/run/docker.sock 的访问权限,可以(微不足道)突破 docker 提供的遏制并获得访问权限主机。显然这是有潜在危险的。 如果 --hostname 参数与 run 命令一起使用,是否有人知道如何在 windows docker 容器中获取相同的信息,以便不再简单地运行“主机名”给你容器ID? 在安全性方面将 docker daemon api 暴露给容器是一种非常糟糕的方法。因为受感染的容器可以访问 docker 并做任何它想做的事情。应该有一些单独的 API 仅用于获取非私人信息。 【参考方案1】:

除非被覆盖,否则主机名似乎是 Docker 1.12 中的短容器 ID

root@d2258e6dec11:/project# cat /etc/hostname
d2258e6dec11

外部

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED                 STATUS                      PORTS               NAMES
d2258e6dec11        300518d26271        "bash"              5 minutes ago       

$ docker -v
Docker version 1.12.0, build 8eab29e, experimental

【讨论】:

是的,这让我很容易在 nodejs 中提取信息。 const os = require('os'); console.log(os.hostname()); 要获取与 Java 中的 Container Id 匹配的主机名,请使用 InetAddress.getLocalHost().getHostName() 有时读取环境变量 $HOSTNAME 的值更简单(例如在 shell 脚本中)。 在 windows 容器上,相当于 COMPUTERNAME env var 如果在 Windows 中工作,请确保在传递到 Docker 引擎 API 之前将 COMPUTERNAME 值小写。【参考方案2】:

我发现容器id可以在/proc/self/cgroup中找到

所以你可以得到 id :

cat /proc/self/cgroup | grep -o  -e "docker-.*.scope" | head -n 1 | sed "s/docker-\(.*\).scope/\\1/"

【讨论】:

不得不稍微调整一下,这对我在 Docker 1.4.1 cat /proc/self/cgroup | grep "docker" | sed s/\\//\\n/g | tail -1 有效 对于 docker 1.6.2 我不得不使用:cat /proc/self/cgroup | grep 'docker' | sed 's/^.*\///' | tail -n1 Aaaa 和 Docker 1.12:cat /proc/1/cgroup | grep 'docker/' | tail -1 | sed 's/^.*\///' | cut -c 1-12 我有点喜欢basename "$(cat /proc/1/cpuset)"basename "$(head /proc/1/cgroup)" 以后如果在docker中使用cgroup namespace和cgroup v2,这个方法可能已经不行了。【参考方案3】:

madeddie 的评论对我来说看起来最优雅:

CID=$(basename $(cat /proc/1/cpuset))

【讨论】:

很高兴能详细说明它的实际作用。如果用户为该容器覆盖主机名,它是否仍然有效?它是否需要容器外的文件系统访问权限?【参考方案4】:

您可以通过 Docker Remote API 使用 unix 套接字从容器内部与 docker 通信:

https://docs.docker.com/engine/reference/api/docker_remote_api/

在容器中,您可以通过检查 $HOSTNAME env var 找出缩短的 docker id。 根据文档,碰撞的可能性很小,我认为对于少量容器,您不必担心。我不知道如何直接获取完整的id。

您可以按照 banyan 回答中所述的类似方式检查容器:

GET /containers/4abbef615af7/json HTTP/1.1

回复:

HTTP/1.1 200 OK
Content-Type: application/json


         "Id": "4abbef615af7......  ",
         "Created": "2013.....",
         ...

或者,您可以将 docker id 传输到文件中的容器。 该文件位于“挂载卷”上,因此它被传输到容器:

docker run -t -i -cidfile /mydir/host1.txt -v /mydir:/mydir ubuntu /bin/bash

docker id(缩短)将在容器中的文件 /mydir/host1.txt 中。

【讨论】:

谢谢,但这与我使用的方法相同,如果在运行 docker 时使用 -h 设置主机名,则会中断。 @Alessandro 我已将有关 -cidfile 参数的信息添加到 docker run。它可以帮助您将 docker id 传递给容器,而不是使用 $HOSTNAME。 太棒了!是的,这是我可以使用的东西!谢谢! 奇怪的是,在 1.11.2 中,env 似乎没有列出 HOSTNAME,但 echo $HOSTNAME 有效。 这根本不起作用,您的 URL 已损坏,现在重定向到错误的文档。 requests.exceptions.MissingSchema: Invalid URL '/containers/1d26a841bf07/json': No schema supplied. Perhaps you meant http:///containers/1d26a841bf07/json?【参考方案5】:

这将从容器中获取完整的容器 ID:

cat /proc/self/cgroup | grep "cpu:/" | sed 's/\([0-9]\):cpu:\/docker\///g'

【讨论】:

【参考方案6】:

警告:在考虑之前您应该了解the security risks of this method。 John的风险总结:

通过让容器访问/var/run/docker.sock,[非常容易] 突破 docker 提供的遏制并获得对主机的访问权限。显然,这是有潜在危险的。


在容器内,dockerId 是您的主机名。 所以,你可以:

在您的容器中安装docker-io package,与主机版本相同 以--volume /var/run/docker.sock:/var/run/docker.sock --privileged 开头 最后,在容器内运行:docker inspect $(hostname)

避免这种情况。只有在您了解风险并明确缓解风险的情况下才这样做。

【讨论】:

我怀疑如果使用了 docker run --hostname 选项,这将不起作用。 如果设置了--hostname,您可以使用此答案中的组合和@Jay Taylor 在接受的答案中的评论:docker inspect $(cat /proc/self/cgroup | grep 'docker' | sed 's/^.*\///' | tail -n1) 来获取有关正在运行的容器的所有信息。 你能引用 docker-io 吗? 我认为它是 npmjs.com/package/docker-io,但这正是 Google 告诉我的,也许不是你的意思。 缓解措施是什么?【参考方案7】:

为了简单起见,

    容器 ID 是您在 docker 中的主机名 容器信息在 /proc/self/cgroup 中可用

要获取主机名,

hostname

uname -n

cat /etc/host

输出可以重定向到任何文件并从应用程序读回 例如:# hostname > /usr/src//hostname.txt

【讨论】:

【参考方案8】:

我发现在 17.09 中有一种最简单的方法可以在 docker 容器中执行此操作:

$ cat /proc/self/cgroup | head -n 1 | cut -d '/' -f3
4de1c09d3f1979147cd5672571b69abec03d606afcc7bdc54ddb2b69dec3861c

或者就像已经被告知的那样,一个较短的版本,带有

$ cat /etc/hostname
4de1c09d3f19

或者简单地说:

$ hostname
4de1c09d3f19

【讨论】:

【参考方案9】:

Docker 默认将主机名设置为容器 ID,但用户可以使用 --hostname 覆盖它。相反,检查/proc

$ more /proc/self/cgroup
14:name=systemd:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
13:pids:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
12:hugetlb:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
11:net_prio:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
10:perf_event:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
9:net_cls:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
8:freezer:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
7:devices:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
6:memory:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
5:blkio:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
4:cpuacct:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
3:cpu:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
2:cpuset:/docker/7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605
1:name=openrc:/docker

这是提取容器 ID 的便捷单行代码:

$ grep "memory:/" < /proc/self/cgroup | sed 's|.*/||'
7be92808767a667f35c8505cbf40d14e931ef6db5b0210329cf193b15ba9d605

【讨论】:

【参考方案10】:

由于/proc/self/cgroup 格式的更改,一些已发布的解决方案已停止工作。这是一个 GNU grep 命令,它应该对格式更改更加健壮:

grep -o -P -m1 'docker.*\K[0-9a-f]64,' /proc/self/cgroup

作为参考,这里是来自 docker 容器内部的 /proc/self/cgroup 的片段,这些片段已经使用此命令进行了测试:

Linux 4.4:

11:pids:/system.slice/docker-cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411.scope
...
1:name=systemd:/system.slice/docker-cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411.scope

Linux 4.8 - 4.13:

11:hugetlb:/docker/afe96d48db6d2c19585572f986fc310c92421a3dac28310e847566fb82166013
...
1:name=systemd:/docker/afe96d48db6d2c19585572f986fc310c92421a3dac28310e847566fb82166013

【讨论】:

【参考方案11】:

您可以使用此命令行来识别当前的容器 ID(使用 docker 1.9 测试)。

awk -F"-|/." '/1:/ print $3' /proc/self/cgroup

然后,向 Docker API(您可以共享 /var/run/docker.sock)发出一点请求以检索所有信息。

【讨论】:

awk -F"-|/." '/1:/ print $3' /proc/self/cgroup【参考方案12】:
awk -F'[:/]' '(($4 == "docker") && (lastId != $NF))  lastId = $NF; print $NF; ' /proc/self/cgroup

【讨论】:

【参考方案13】:

我认为上述所有内容的“问题”在于它取决于 docker 本身或其实现的某个实现约定以及它如何与 cgroups 和 /proc 交互,而 不是通过作为 OCI 规范一部分的承诺的、公共的、API、协议或约定。

因此,这些解决方案是“脆弱的”,并且在实现发生变化或约定被用户配置覆盖时,可能会在最意想不到的时候中断。

容器和图像 ID 应该由启动容器实例的组件注入到 r/t 环境中,如果没有其他原因 允许其中运行的代码使用该信息来唯一标识自己以进行日志记录/跟踪等...

只是我的 0.02 美元,YMMV...

【讨论】:

【参考方案14】:

顺便说一句,如果你有容器的 pid 并且想要获取该容器的 docker id,一个好方法是结合上面的 sed 魔法使用 nsenter:

nsenter -n -m -t pid -- cat /proc/1/cgroup | grep -o -e "docker-.*.scope" | head -n 1 | sed "s/docker-\(.*\).scope/\\1/"

【讨论】:

【参考方案15】:

使用docker inspect

$ docker ps # get conteiner id
$ docker inspect 4abbef615af7
[
    "ID": "4abbef615af780f24991ccdca946cd50d2422e75f53fb15f578e14167c365989",
    "Created": "2014-01-08T07:13:32.765612597Z",
    "Path": "/bin/bash",
    "Args": [
        "-c",
        "/start web"
    ],
    "Config": 
        "Hostname": "4abbef615af7",
...

可以通过如下方式获取ip。

$ docker inspect -format=" .NetworkSettings.IPAddress " 2a5624c52119
172.17.0.24

【讨论】:

这不是我的意思。我需要能够从容器 inside 获取这些信息。基本上我需要一种方法来了解我从内部运行的容器的 ID。

以上是关于如何从容器本身获取 Docker Linux 容器信息?的主要内容,如果未能解决你的问题,请参考以下文章

如何从主机获取 Docker 容器的 IP 地址

如何在 docker 中从一个容器获取数据到另一个容器?我收到 ECONNREFUSED 错误

如何从 docker 容器中获取 docker 主机的 IP 地址

如何从 Docker 容器中获取主机的 udev 事件?

如何从 docker 容器中获取节点版本?

如何从docker容器中获取docker主机的IP地址