如何获取 Docker 容器的 IP 地址

想知道您正在运行的 docker 容器的 IP 地址是什么? 您可以检查正在运行的容器以获取该信息。

sudo docker container inspect container_name_or_ID

不知道容器的名称或 ID? 使用命令 sudo docker ps.

inspect 命令为您提供有关您正在检查的容器的许多详细信息。 走到尽头,看看 Networks 部分以获取容器的 IP 地址。

您也可以使用 grep 命令来获取与字符串“IPAddress”匹配的行。

如果您的容器有多个 IP 地址,请不要惊慌。 这并不罕见。 要理解这一点,您需要了解容器如何相互通信。

我将在下一节中向您解释这一点,然后是其他一些获取正在运行的 docker 容器的 IP 地址的方法。

docker 容器如何通信?

Docker 是一种使用容器化技术向大众打包和交付软件的工具。 软件可以有多种用途,从可能的简单文本处理到完整的网络服务器,托管您的私人文件。 这些软件中的每一个都被分解为微服务,然后打包为容器。 根据软件的用途,一项服务可能需要与另一项服务进行通信。

为了 example,考虑 WordPress。 有两种服务,一种是服务于前端的 Web 服务器,另一种是后端,即数据库。 前端必须与数据库通信,否则它将无法工作。

这种通信是通过使至少两个网络接口与这两个容器中的每一个相关联来实现的,这两个接口都连接到同一个网络。 这个网络被称为“码头网络”。

码头工人网络

将 docker 网络视为可用 IP 地址池。 如果两个容器从同一个池中获取 IP 地址,它们将能够相互通信。

主要有两种类型的网络,默认或预定义的网络和用户定义的网络。

您可以使用以下命令获取网络列表

docker network ls

考虑以下我的清单:

❯ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
272ff2e44dc2   bridge    bridge    local
5e4a3f5e99dd   host      host      local
cdaef1e49ddc   none      null      local

忽略最后两个并专注于第一个网络。 这 bridge 如果没有明确指定,network 是每个容器都将连接到的默认网络。 您可以通过运行 docker network inspect bridge 命令。

我将过滤输出,因为对于这个演示,我不需要所有数据 inspect 要爆炸了。

❯ docker network inspect -f '{{json .IPAM.Config}}' bridge | jq -r .[].Subnet
172.17.0.0/16

如果您没有安装 jq,请使用您的发行版的包管理器安装它。

这些 docker 网络中的每一个都有一个子网,在 bridge 网络,这个子网是 172.17.0.0/16。 这意味着总共有 65,534 – 1 = 65,533 个可用主机或 IP 地址。 因为网关分配了172.17.0.1,所以我扣了一个。 您也可以使用以下命令看到这一点

docker network inspect -f '{{json .IPAM.Config}}' bridge | jq -r .[].Gateway

检查 docker 容器的 IP 地址

有几种方法可以检查 IP 地址[es] 与您的容器相关联,这里是所有它们的列表,包括命令示例。

方法一:通过检查容器

inspect docker 的子命令非常有用。 可以使用以下方法检查容器 docker container inspect [CONTAINER ID]|[CONTAINER NAME] 命令。

检查容器意味着尽可能多地获取有关容器的信息,从端口、环境变量到挂载点、cgroup 数据等。可以从中提取 IP 地址。

如果你运行 inspect 容器上的命令,您将获得大量 JSON 格式的信息。 向下滚动直到找到钥匙 NetworkSettings,在那里寻找子键 IPAddress. 那是您容器的 IP 地址。

要执行的命令如下所示

docker container inspect [CONTAINER ID]|[CONTAINER NAME]

这是我的输出(截断)

> docker container inspect ubuntu-ip
.
.
.
"NetworkSettings": {
.
.
.
            "IPAddress": "172.17.0.2",
.
.
.

您可以像这样过滤输出,而不是滚动浏览所有内容:

docker container inspect -f '{{ .NetworkSettings.IPAddress }}' CONTAINER_ID_OR_NAME

这是过滤后的输出:

❯ docker container inspect -f '{{ .NetworkSettings.IPAddress }}' ubuntu-ip 
172.17.0.2

如果要获取与特定网络关联的 IP 地址,请使用如下命令

docker container inspect -f '{{ .NetworkSettings.Networks.[NETWORK NAME].IPAddress }}' CONTAINER_ID_OR_NAME

示例输出:

❯ docker container inspect -f '{{ .NetworkSettings.Networks.bridge.IPAddress }}' ubuntu-ip 
172.17.0.2

方法二:使用容器的外壳

这是最直接的方法,但也 我不推荐的东西.

在此方法中,您将 stdin|stdout 与容器附加并运行 ip 命令(或其他显示与 NIC 关联的 IP 地址的命令)。

我不推荐这样做的原因是许多图像非常轻量级,并且不包含 ip 命令(或类似的东西)。

采取 ubuntu:20.04 图像作为 example像下面这样启动一个容器

docker run --rm --name ubuntu-ip -d ubuntu:20.04 sleep 1d

为了保持容器运行,我使用了 sleep 1d 命令。

现在在容器内启动一个 shell 进程并像这样附加你的 stdin|stdout

docker exec -ti ubuntu-ip sh

进入此容器后,尝试运行 ip 或者 ifconfig. 您将看到类似以下内容:

❯ docker exec -ti ubuntu-ip sh
# ip
sh: 1: ip: not found
# ifconfig
sh: 2: ifconfig: not found

要使这些命令正常工作,您需要安装相关软件包。 要得到 ip 命令,安装 iproute2 打包并重新运行命令为 ip a

# apt update -qq                                       
6 packages can be upgraded. Run 'apt list --upgradable' to see them.
# apt install iproute2 -yqq
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
4: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

现在您可以看到与卡关联的 IP 地址 [email protected] 为 172.17.0.2。

请注意此容器所属的网络。 由于我没有创建用户自定义网络并将其连接到这个容器,所以它连接到了桥接网络,这就是为什么这个IP的网络是172.17.0.0

这种方法确实有效,虽然它的工作量更大且重现性不强,但它很直观。 与此相比,下一个方法应该要好得多。

方法3:通过检查网络本身

每当容器连接到网络时,从网络中也可以看到连接的容器,以及分配给这些容器的 IP 地址。

由于我的容器连接到桥接网络,我可以使用以下命令检查网络

docker network inspect [NETWORK NAME][NETWORK ID]

在这里,我将使用名称而不是 id, bridge

docker network inspect bridge

而不是向下滚动到 Containers 部分,我将使用 jq 这次过滤输出。

❯ docker network inspect bridge | jq .[].Containers
{
  "1c76f35ce42ca0d31cfcc79da80eadfa4f69cb82e292e249ee1bd75d83a8e4ba": {
    "Name": "ubuntu-ip",
    "EndpointID": "44d6b85348d6274b4ee779f9d3617d184ccfd3bad228ee652141d9b4157c50ae",
    "MacAddress": "02:42:ac:11:00:02",
    "IPv4Address": "172.17.0.2/16",
    "IPv6Address": ""
  },
  "50a4f195d8eae6b6b714e8aa058c6058dbe91d0a272c8ca826d4442df1c63885": {
    "Name": "ip",
    "EndpointID": "d4e72a4df81ee7023386df9d96676d9c291e2902349eb453338b8e0145a610fd",
    "MacAddress": "02:42:ac:11:00:03",
    "IPv4Address": "172.17.0.3/16",
    "IPv6Address": ""
  }
}

为了证明这一点,我部署了另一个名为 ip. 您可以在上面的 JSON 对象中看到容器和 IP 地址。 现在在这里提取特定容器的 IP 稍微困难一些。

如果您知道容器 ID,则可以使用 jq 像这样

docker network inspect bridge | jq '.[].Containers."[CONTAINER ID]".IPv4Address'

这是一个 example

❯ docker network inspect bridge | jq '.[].Containers."1c76f35ce42ca0d31cfcc79da80eadfa4f69cb82e292e249ee1bd75d83a8e4ba".IPv4Address' -r
172.17.0.2/16

很多时候你不记得容器id,所以如果你想只从容器名称中获取IP,你需要一些知识 jq (或者只是重用以下命令)。

docker network inspect -f '{{json .Containers}}' bridge | 
    jq '..|if type == "object" and has("Name") then select(.Name=="[CONTAINER NAME]") | .IPv4Address else empty end' -r

将容器名称放在 select 发挥作用,见证奇迹发生。

❯ docker network inspect -f '{{json .Containers}}' bridge | 
    jq '..|if type == "object" and has("Name") then select(.Name=="ubuntu-ip") | .IPv4Address else empty end' -r

172.17.0.2/16

你更喜欢哪种方法? 方法一大概

这些都是您可以获得IP地址的方法[es] 码头集装箱。 第二种方法虽然直观但不可重现。 大多数时候,它是第一个使用的方法,因为它最简单并且可以完成工作。

但是有时您可能想检查哪些容器连接到某个网络并获取该网络上的 IP 地址。 在这种情况下,检查网络并获取 IP 是有意义的。 您可以从这样的网络获取分配给它们的所有容器名称和 IP

❯ docker network inspect -f '{{json .Containers}}' bridge | 
    jq '.. | if type=="object" and has("Name") then {(.Name): .IPv4Address} else empty end'

{
  "ubuntu-ip": "172.17.0.2/16"
}
{
  "ip": "172.17.0.3/16"
}

改变 bridge 到其他网络,您将像这样获得所有容器及其 ​​IP 地址。

这就是今天的内容。 我希望这篇文章对你有所帮助。 如果您有任何疑问,请在下面的评论中告诉我。