如何从容器本身获取 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 容器信息?的主要内容,如果未能解决你的问题,请参考以下文章