深入 Docker 网络

DockerDockerBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

介绍

在本实验中,我们将基于 Docker 网络的基础知识,深入探讨高级 Docker 网络概念。我们将深入研究三种主要的网络模式:Bridge(桥接)、Host(主机)和 None(无网络)。我们还将学习如何创建自定义网络、跨不同网络连接容器,并理解每种网络模式对容器通信和隔离的影响。通过动手实践,你将获得扎实的 Docker 网络实践基础。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("Docker")) -.-> docker/NetworkOperationsGroup(["Network Operations"]) docker(("Docker")) -.-> docker/ContainerOperationsGroup(["Container Operations"]) docker/ContainerOperationsGroup -.-> docker/run("Run a Container") docker/ContainerOperationsGroup -.-> docker/exec("Execute Command in Container") docker/ContainerOperationsGroup -.-> docker/inspect("Inspect Container") docker/NetworkOperationsGroup -.-> docker/network("Manage Networks") subgraph Lab Skills docker/run -.-> lab-389047{{"深入 Docker 网络"}} docker/exec -.-> lab-389047{{"深入 Docker 网络"}} docker/inspect -.-> lab-389047{{"深入 Docker 网络"}} docker/network -.-> lab-389047{{"深入 Docker 网络"}} end

自定义桥接网络

虽然 Docker 提供了默认的桥接网络,但创建自定义桥接网络可以更好地隔离和控制容器之间的通信。

  1. 首先,让我们查看当前的 Docker 网络列表:
docker network ls

你应该会看到类似以下的输出:

NETWORK ID     NAME      DRIVER    SCOPE
296d1b460b17   bridge    bridge    local
91199fc6ad2e   host      host      local
1078d2c781b6   none      null      local
  1. 现在,让我们创建一个自定义桥接网络:
docker network create my-custom-bridge
  1. 再次列出所有 Docker 网络以验证创建结果:
docker network ls

你现在应该会在输出中看到 my-custom-bridge

NETWORK ID     NAME               DRIVER    SCOPE
296d1b460b17   bridge             bridge    local
91199fc6ad2e   host               host      local
7215f99d0080   my-custom-bridge   bridge    local
1078d2c781b6   none               null      local
  1. 在自定义桥接网络上启动两个容器并安装 ping 工具:
docker run --network=my-custom-bridge --name container1 -d nginx
docker run --network=my-custom-bridge --name container2 -d nginx

现在,让我们在这两个容器中安装 ping 工具。我们需要这样做,因为默认的 Nginx 镜像不包含 ping:

docker exec container1 apt-get update && docker exec container1 apt-get install -y iputils-ping
docker exec container2 apt-get update && docker exec container2 apt-get install -y iputils-ping
  1. 测试容器之间的通信:
docker exec container1 ping -c 4 container2

你应该会看到成功的 ping 响应,这表明在同一自定义桥接网络上的容器可以使用容器名称进行通信。这是因为 Docker 内置的 DNS 会在同一网络中将容器名称解析为其 IP 地址。

如果你没有看到成功的 ping 响应,请确保两个容器都在运行(docker ps),并且你已经正确安装了 ping 工具。

跨网络连接容器

Docker 允许容器连接到多个网络,从而实现不同网络上的容器之间的通信。这在你想隔离某些容器但仍允许它们之间进行特定通信时特别有用。

  1. 首先,让我们创建第二个自定义桥接网络:
docker network create my-second-bridge
  1. 验证网络创建:
docker network ls

你现在应该会看到两个自定义网络:

NETWORK ID     NAME               DRIVER    SCOPE
296d1b460b17   bridge             bridge    local
91199fc6ad2e   host               host      local
7215f99d0080   my-custom-bridge   bridge    local
8a15f99d0081   my-second-bridge   bridge    local
1078d2c781b6   none               null      local
  1. container2 连接到新网络:
docker network connect my-second-bridge container2

此命令将 container2 添加到 my-second-bridge 网络,同时保持其与 my-custom-bridge 的连接。

  1. 在第二个网络上创建一个新容器:
docker run --network=my-second-bridge --name container3 -d nginx
docker exec container3 apt-get update && docker exec container3 apt-get install -y iputils-ping
  1. 测试所有容器之间的通信:
docker exec container1 ping -c 2 container2
docker exec container1 ping -c 2 container3
docker exec container2 ping -c 2 container3

注意结果:

  • container1 可以与 container2 通信(它们在同一个网络上)
  • container1 无法与 container3 通信(它们在不同的网络上)
  • container2 可以与 container1container3 通信(它连接到了两个网络)

如果 container1 能够 ping 通 container3,说明你的网络隔离可能存在问题。

主机网络模式

主机网络模式移除了容器与 Docker 主机之间的网络隔离,允许容器直接使用主机的网络。这对于最大化性能非常有用,但由于减少了隔离性,会带来一定的安全隐患。

  1. 使用主机网络模式创建一个容器:
docker run --network host --name host-container -d nginx
  1. 验证当前的网络列表:
docker network ls

你不会看到这个容器的新网络,因为它直接使用了主机的网络。

  1. 验证容器是否使用了主机的网络:
docker inspect --format '{{.HostConfig.NetworkMode}}' host-container

这应该会输出 host

  1. 尝试从主机访问 Nginx 的默认页面:
curl localhost:80

你应该会看到 Nginx 的欢迎页面。这是因为容器使用了主机的网络,而 Nginx 正在监听主机网络接口的 80 端口。

注意:如果你的主机上已经有服务运行在 80 端口,这一步可能会失败。在这种情况下,你需要先停止现有的服务。

None 网络模式

'none' 网络模式创建的容器没有任何网络接口,完全将其与网络隔离。这对于最大程度的安全隔离非常有用,但也意味着容器无法通过网络进行任何通信。

  1. 创建一个没有网络的容器:
docker run --network none --name isolated-container -d alpine sleep infinity
  1. 验证当前的网络列表:
docker network ls

你不会看到这个容器的新网络,因为它没有连接到任何网络。

  1. 验证容器是否没有网络接口:
docker exec isolated-container ip addr

你应该只会看到回环接口(lo)。不会有任何 eth0 或其他网络接口。

  1. 尝试从隔离的容器中 ping Google:
docker exec isolated-container ping -c 2 google.com

这应该会失败,并显示“Network is unreachable”(网络不可达)错误,因为容器没有网络访问权限。

网络别名与服务发现

Docker 网络支持使用网络别名进行服务发现,这对于创建弹性、可扩展的应用程序非常有用。此功能允许多个容器响应相同的 DNS 名称,从而实现基本的负载均衡。

  1. 为本实验创建一个新的桥接网络:
docker network create service-network
  1. 验证网络创建:
docker network ls

你应该会在列表中看到 service-network

  1. 创建两个具有相同网络别名的容器:
docker run -d --network service-network --network-alias myservice --name service1 nginx
docker run -d --network service-network --network-alias myservice --name service2 nginx
  1. 创建一个客户端容器并使用 nslookup 解析服务:
docker run --rm --network service-network appropriate/curl nslookup myservice

你应该会看到返回的两个容器 IP,这表明 Docker 的内置 DNS 服务器正在两个容器之间进行负载均衡。

  1. 测试多次访问服务:
for i in {1..4}; do docker run --rm --network service-network appropriate/curl ping -c 1 myservice; done

你应该会看到来自两个容器的响应,这展示了基本的负载均衡。Docker DNS 服务器在解析 myservice 时会在两个 IP 地址之间交替选择。

PING myservice (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.106 ms

--- myservice ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.106/0.106/0.106 ms
PING myservice (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.119 ms

--- myservice ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.119/0.119/0.119 ms
PING myservice (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.097 ms

--- myservice ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.097/0.097/0.097 ms
PING myservice (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.140 ms

--- myservice ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.140/0.140/0.140 ms

总结

在这个高级 Docker 网络实验中,我们探索了几个关键概念:

  1. 自定义桥接网络,用于改进容器隔离和通信
  2. 跨多个网络连接容器
  3. 主机网络模式,用于直接访问主机的网络栈
  4. None 网络模式,用于完全的网络隔离
  5. 网络别名和服务发现,用于构建可扩展的应用程序

Docker 中的这些高级网络功能为设计复杂的多容器应用程序提供了强大的工具,能够精确控制容器之间的通信和隔离。理解这些概念对于设计高效、安全和可扩展的容器化应用程序至关重要。

请记住,虽然 Docker 网络提供了极大的灵活性,但在设计容器网络架构时,考虑安全影响非常重要。始终遵循最小权限原则,仅暴露必要的端口和服务。

随着你继续使用 Docker,你会发现这些网络概念在编排复杂应用程序和微服务架构时非常宝贵。定期练习这些概念,以便熟练掌握 Docker 网络的有效管理。