简介
Docker 容器是独立的环境,可在不干扰主机系统的情况下运行应用程序。默认情况下,Docker 会创建虚拟网络来隔离容器流量,但有时你可能希望容器直接使用主机的网络。
在这个实验中,你将学习如何配置 Docker 容器以使用主机网络。你将探索默认桥接网络和主机网络之间的差异,了解何时使用主机网络,并通过实际示例亲身体验其优势。
了解 Docker 网络类型
在我们配置容器使用主机网络之前,让我们先探索一下 Docker 中可用的不同网络类型,并了解它们的用途。
检查可用的 Docker 网络
让我们从检查系统上的默认 Docker 网络开始:
在你的 LabEx 环境中打开一个终端。
运行以下命令列出所有 Docker 网络:
docker network ls
你应该会看到类似如下的输出:
NETWORK ID NAME DRIVER SCOPE
1234567890ab bridge bridge local
0987654321cd host host local
abcdef123456 none null local
Docker 提供了三种默认网络:
bridge:容器的默认网络host:直接使用主机的网络none:无网络(容器处于隔离状态)
了解默认桥接网络
当你在运行容器时不指定网络,Docker 会将其连接到默认桥接网络。这会为每个容器创建一个虚拟网络接口,并允许容器之间以及与外部网络进行通信。
让我们来实际操作一下:
- 使用默认桥接网络运行一个简单的 nginx 容器:
docker run --name nginx-bridge -d -p 8080:80 nginx:alpine
- 检查容器的网络设置:
docker inspect nginx-bridge --format '{{json .NetworkSettings.Networks}}' | jq
你应该会看到输出显示容器已连接到桥接网络并拥有自己的 IP 地址。
- 通过向映射端口发出请求来验证主机是否可以访问该容器:
curl http://localhost:8080
你应该会看到 nginx 欢迎页面的 HTML 内容。
这展示了桥接网络的工作方式——容器有自己的 IP 地址,容器内的 80 端口被映射到主机的 8080 端口。
使用主机网络模式运行容器
现在让我们来探索如何使用主机网络运行容器,并了解它与桥接网络的区别。
使用主机网络
当你使用主机网络模式时,容器会直接共享主机的网络命名空间。这意味着:
- 容器使用主机的 IP 地址
- 无需进行端口映射
- 容器可以访问主机上的所有网络接口
- 如果容器尝试使用主机上已被占用的端口,可能会发生端口冲突
让我们使用主机网络运行一个容器:
- 停止并移除之前的 nginx 容器以释放 80 端口:
docker stop nginx-bridge
docker rm nginx-bridge
- 现在使用主机网络运行一个新的 nginx 容器:
docker run --name nginx-host --network host -d nginx:alpine
注意,我们不需要指定 -p 标志进行端口映射,因为容器将直接使用主机的网络栈。
- 检查容器的网络设置:
docker inspect nginx-host --format '{{json .NetworkSettings.Networks}}' | jq
你会看到容器已连接到主机网络。
- 直接在主机的 80 端口访问 nginx 服务器:
curl http://localhost:80
你应该会看到 nginx 欢迎页面的 HTML 内容。
理解差异
让我们比较一下这两种方法:
使用桥接网络(默认):
- 容器有自己的 IP 地址
- 需要进行端口映射才能访问容器服务
- 有额外的网络层用于隔离
- 由于隔离性,安全性更高
使用主机网络:
- 容器使用主机的 IP 地址
- 无需进行端口映射
- 可以直接访问主机的网络接口
- 网络性能更好
- 容器和主机之间的隔离性较差
比较网络性能和行为
现在,让我们进行一些测试,来了解 Docker 中桥接网络和主机网络之间的实际差异。
测试网络性能
首先,我们创建一个使用桥接网络的容器和一个使用主机网络的容器,然后比较它们的性能。
- 停止并移除之前的 nginx 容器:
docker stop nginx-host
docker rm nginx-host
- 创建一个使用桥接网络的新容器来测试性能:
docker run --name bridge-test -d --network bridge nginx:alpine
- 创建另一个使用主机网络的容器:
docker run --name host-test -d --network host nginx:alpine
- 使用
docker exec在每个容器中运行一个简单的网络测试:
对于桥接网络容器:
docker exec bridge-test sh -c "time wget -q -O /dev/null http://google.com"
对于主机网络容器:
docker exec host-test sh -c "time wget -q -O /dev/null http://google.com"
比较执行时间。通常,主机网络容器的性能会稍好一些,因为它避免了额外的网络层。
检查网络接口
让我们检查两个容器中的网络接口:
- 对于桥接网络容器:
docker exec bridge-test ip addr show
你会看到这个容器有自己的网络接口,与主机隔离。
- 对于主机网络容器:
docker exec host-test ip addr show
你会注意到这个容器的网络接口与主机系统完全相同,包括所有物理网络接口。
- 与主机的网络接口进行比较:
ip addr show
主机网络容器的接口应该与主机系统的接口相匹配。
理解端口冲突
使用主机网络时,如果容器尝试使用主机上已被占用的端口,就会发生端口冲突:
- 停止并移除所有正在运行的容器:
docker stop bridge-test host-test
docker rm bridge-test host-test
- 在主机上使用 8080 端口启动一个服务:
python3 -m http.server 8080 &
- 现在尝试运行一个使用主机网络且也想使用 8080 端口的容器:
docker run --name conflict-test --network host -d -p 8080:80 nginx:alpine
你应该会看到一个错误,因为主机上的 8080 端口已被占用。
- 清理 Python HTTP 服务器:
kill %1
这展示了主机网络的一个潜在缺点——你需要注意与主机的端口冲突。
主机网络的实际用例
现在,让我们探索一些使用主机网络有益的实际用例,并实现一个实际示例。
何时使用主机网络
主机网络在以下场景中特别有用:
- 对性能要求极高的应用程序:当网络性能至关重要,且你想避免桥接网络带来的额外开销时。
- 网络监控工具:需要捕获或分析主机上网络流量的应用程序。
- 使用多个端口的应用程序:当你的服务使用多个端口或动态分配端口时。
- 访问硬件网络接口:当容器需要直接访问物理网络接口时。
使用主机网络实现网络监控工具
让我们实现一个实际示例:一个简单的网络监控容器,它需要访问主机的网络接口。
- 首先,使用主机网络运行一个网络监控工具:
docker run --name netmon --network host -d alpine:latest sleep infinity
这个容器将无限期运行,允许我们在其中执行命令。
- 现在,让我们在容器内捕获一些网络流量:
docker exec netmon sh -c "apk add --no-cache tcpdump && tcpdump -c 10 -i any -n"
上述命令:
- 在容器中安装
tcpdump工具 - 从任何接口捕获 10 个数据包
- 显示数字输出(不进行主机名解析)
由于我们使用的是主机网络,容器可以直接访问主机的所有网络接口。
- 让我们检查是否可以捕获到特定主机服务的流量:
## 打开一个新的终端窗口并生成一些流量
curl http://localhost:80 &
## 在原终端中运行:
docker exec netmon sh -c "apk add --no-cache tcpdump && tcpdump -c 5 -i any port 80 -n"
你应该会看到容器正在捕获 80 端口上的 HTTP 流量。
这展示了主机网络如何使容器能够访问主机的网络接口并捕获流量,而使用桥接网络则会更困难。
在 Docker Compose 文件中使用主机网络
对于使用 Docker Compose 的人来说,你可以在 docker-compose.yml 文件中配置服务使用主机网络:
version: "3"
services:
web:
image: nginx:alpine
network_mode: "host"
此配置将使 web 服务使用主机的网络栈。
安全考量与最佳实践
在 Docker 容器中使用主机网络时,了解其安全影响并遵循最佳实践非常重要。
主机网络的安全影响
使用主机网络会降低容器与主机系统之间的隔离性。这带来了以下几个安全方面的影响:
- 网络隔离性降低:使用主机网络的容器可以访问主机上的所有网络接口和端口。
- 潜在的端口冲突:容器内的服务可能会与主机上运行的服务发生端口冲突。
- 攻击面增大:如果容器被攻破,攻击者可能会更直接地访问主机网络。
使用主机网络的最佳实践
在使用主机网络时,请遵循以下最佳实践:
- 限制容器权限:即使使用主机网络,也要遵循最小权限原则:
## 运行一个使用主机网络但移除部分权限的容器
docker run --name secure-host-net --network host --cap-drop ALL --cap-add NET_ADMIN -d alpine:latest sleep infinity
- 仅在必要时使用主机网络:仅对真正需要的容器使用主机网络,而不是将其作为默认选择。
- 定期进行安全审计:更密切地监控使用主机网络的容器,以发现潜在的安全问题。
- 尽可能使用只读文件系统:
## 运行一个使用主机网络且使用只读文件系统的容器
docker run --name readonly-host-net --network host --read-only -d alpine:latest sleep infinity
- 清理未使用的容器:
## 移除所有已停止的容器(清理操作)
docker container prune -f
清理实验环境
让我们清理在本次实验中创建的所有容器:
## 列出所有容器
docker ps -a
## 停止所有正在运行的容器
docker stop $(docker ps -q) 2> /dev/null || true
## 移除所有容器
docker rm $(docker ps -a -q) 2> /dev/null || true
## 验证所有容器已被移除
docker ps -a
运行这些命令后,你应该看不到任何列出的容器。
何时选择桥接网络与主机网络
总结一下何时使用每种网络类型:
在以下情况下使用桥接网络(默认):
- 你需要容器之间的隔离。
- 你需要精确控制端口映射。
- 你的应用程序不需要直接访问主机网络接口。
- 安全是首要考虑因素。
在以下情况下使用主机网络:
- 网络性能至关重要。
- 你需要直接访问主机网络接口。
- 你的容器需要使用多个端口或动态端口分配。
- 你需要监控网络流量。
- 容器必须与主机具有相同的 IP 地址。
总结
在本次实验中,你学到了:
- Docker 桥接网络和主机网络之间的区别
- 如何使用
--network host标志以主机网络模式运行 Docker 容器 - 与桥接网络相比,主机网络的性能优势
- 主机网络有益的实际用例
- 使用主机网络时的安全考量和最佳实践
主机网络消除了容器与主机之间的网络隔离,使容器能够直接访问主机的网络接口。这可以提高性能、简化配置,并使某些类型的应用程序(如网络监控工具)能够正常运行。
请记住,虽然主机网络有一定的优势,但它也会降低隔离性,并可能带来安全问题。始终遵循最佳实践,仅在实际用例确实需要时才使用主机网络。



