logo
0
0
WeChat Login
docs(network): 优化文档描述

Docker 网络

Docker 网络是容器之间通信的基础设施,为容器提供安全、可控的互联能力。在 Docker 中,每个容器都可以加入一个或多个网络,并通过这些网络进行通信,其方式与物理机或虚拟机在传统网络中的通信类似。

常见 Docker 网络命令

在学习各种网络类型之前,我们先来看看 Docker 中常用的网络相关命令。

列出所有网络

docker network ls

创建自定义网络

docker network create [options] ${network_name}

可选的 options 有:

  • -d,--driver:指定驱动类型,默认是 bridge,即单机上的自定义桥接网络。支持 overlay Docker Swarm / 集群下跨主机网络,host 共享宿主机网络(一般不通过 create 创建)

  • --subnet:指定网段

    docker network create --subnet 172.20.0.0/16 my-net
  • --ip-range:容器使用的 IP 范围

    docker network create \ --subnet 172.20.0.0/16 \ --ip-range 172.20.1.0/24 \ my-net
  • ...

查看网络详情

docker network inspect ${network_name}

将容器连接到网络

docker network connect ${network-name} ${container-name}

断开容器与网络的连接

docker network disconnect ${network-name} ${container-name}

删除网络

删除指定名称的网络

docker network rm ${network-name}

删除所有未使用的网络

docker network prune

Docker 网络类型

Bridge 网络(桥接网络)

Bridge 网络使用 Docker 默认的 bridge 网络驱动。当你创建一个容器而不指定网络时,它会自动连接到默认的 bridge 网络。Bridge 网络在单机环境下使用非常广泛,它通过软件网桥实现容器间的通信。

工作原理

安装 Docker 时,会自动在宿主机上创建一个名为 docker0 的虚拟网桥:

ifconfig

它就像一个虚拟交换机。默认的 bridge 网络一般使用 172.17.0.0/16 网段(若该网段已被占用,Docker 会自动选择其他可用网段,如 172.18.0.0/16)。每当启动一个容器,Docker 会为其创建一对 veth(虚拟以太网)设备:一端连接到容器内部作为 eth0 网卡,另一端连接到 docker0 网桥上。这样,所有连接到同一网桥的容器就处于同一个二层网络中,可以通过 IP 地址互相通信。容器访问外部网络时,流量经由 docker0 网桥转发,并通过宿主机的 NAT(iptables)规则进行地址转换后出站。

默认 Bridge 网络

让我们先来看看默认 bridge 网络的行为。

我们先构建一个装有 ping、curl 等工具的 nginx 镜像,方便我们在容器内观察网络行为。首先构建镜像:

docker build -t my-nginx nginx

查看默认 bridge 网络信息:

docker network inspect bridge

启动两个容器,分别为 container1container2

docker run -d --name container1 my-nginx docker run -d --name container2 my-nginx

查看容器的网络配置:

docker inspect container1 -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker inspect container2 -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'

请记下上面输出的 container2 的 IP 地址,下一步会用到。

在容器 container1 中,尝试通过 IP 访问容器 container2(将 ${container2_ip} 替换为上一步查到的实际 IP):

docker exec -it container1 curl http://${container2_ip}

Docker 默认的 bridge 网络存在通信限制:容器间只能通过易变的 IP 地址互相访问,无法使用固定的容器名称作为域名进行通信。例如,下面的命令会报错 Domain name not found

docker exec -it container1 curl http://container2

这种 IP 依赖会导致服务地址变更时需要人工调整配置,增加维护成本。通过创建自定义 bridge 网络,容器可通过稳定的名称直接互访,这种自动化的服务发现机制正是 Docker Compose 实现容器编排的基础——编排工具会自动创建专用网络,使多容器应用能够通过服务名称维持稳定的通信链路。

自定义 Bridge 网络

这一节内容,我们看看自定义 bridge 网络的优势。

首先创建自定义网络:

docker network create --driver bridge --subnet=172.20.0.0/16 --gateway=172.20.0.1 my-bridge-network

连续启动两个容器,连接到自定义网络 my-bridge-network 中:

docker run -d --name custom-container1 --network my-bridge-network my-nginx docker run -d --name custom-container2 --network my-bridge-network my-nginx

现在试试通过容器名称访问:

docker exec -it custom-container1 curl http://custom-container2

可以看到,在自定义 bridge 网络中,容器之间可以直接通过容器名称通信,不再需要依赖 IP 地址。

为什么自定义 bridge 网络支持容器名称解析,而默认 bridge 网络不行?

核心原因在于 DNS 服务的启用机制不同。自定义 bridge 网络会启用 Docker 内置的 DNS 服务器(127.0.0.11),容器可通过名称直接解析其他容器的 IP 地址;而默认的 bridge 网络(即 docker0 虚拟网桥)不提供容器名称解析功能,容器间只能通过 IP 地址通信。

我们可以通过查看容器内的 /etc/resolv.conf 来验证这一点。

自定义 bridge 网络中的容器:

docker exec custom-container1 cat /etc/resolv.conf
nameserver 127.0.0.11 options ndots:0

DNS 指向 Docker 内置 DNS 服务器 127.0.0.11,所以支持容器名称解析。

默认 bridge 网络中的容器:

docker exec container1 cat /etc/resolv.conf
nameserver xx.xx.xx.xx options ndots:0

DNS 直接使用宿主机的 DNS 配置,没有 Docker 内置 DNS 的支持,因此无法通过容器名称互访。

使用自定义 Bridge 网络演示 Web 应用与 Redis 通信

这个案例展示了在实际应用中如何使用自定义 bridge 网络。

首先,创建一个简单的 Web 应用。构建 web-app 镜像:

docker build -t web-app web-app

然后创建网络 web-app-network

docker network create web-app-network

运行 Redis 容器:

docker run -d --name redis-server --network web-app-network redis:alpine

运行 Web 应用容器:

docker run -d --name web-app --network web-app-network -p 5000:5000 web-app

web-app 应用中通过容器名称 redis-server 连接 Redis(详见 web-app/app.py),这正是自定义 bridge 网络提供 DNS 解析的体现。

现在可以测试应用了:

# 访问应用 curl http://localhost:5000 # 多次访问,观察计数器增加 curl http://localhost:5000 curl http://localhost:5000 # 查看 Redis 中的数据 docker exec -it redis-server redis-cli get hits

清理环境,删除本案例创建的容器、网络和镜像。

Host 网络

Host 网络移除了容器和 Docker 主机之间的网络隔离,直接使用主机的网络。

特点:

  • 最佳网络性能
  • 直接使用主机的网络栈
  • 没有网络隔离
  • 端口直接绑定到主机上

接下来,我们使用 Host 网络运行 Nginx 服务器。注意这里不需要 -p 端口映射,因为 host 网络下容器直接使用宿主机的网络栈:

docker run -d --name nginx-host --network host my-nginx

对比 bridge 网络下需要 -p 80:80 才能从宿主机访问容器服务,host 网络下容器的端口直接绑定在宿主机上。

直接在宿主机上访问 Nginx 服务(默认监听 80 端口):

curl http://localhost:80

由于容器与宿主机共享网络,端口冲突是 host 网络下需要特别注意的问题。当我们再启动一个同样监听 80 端口的 Nginx 容器时,会因为端口被占用而启动失败:

docker run -d --name nginx-host2 --network host my-nginx docker ps -a docker logs nginx-host2

清理环境:

docker rm -f nginx-host nginx-host2

None 网络

None 网络完全禁用了容器的网络功能,容器只有 lo(loopback)接口,没有任何外部网络连接。

特点:

  • 完全隔离的网络环境
  • 容器只有 loopback 接口,无法访问外部网络
  • 适用于不需要网络的批处理任务,或对安全隔离要求极高的场景

启动一个使用 none 网络的容器,验证其网络状态:

docker run --rm --network none alpine ifconfig

可以看到输出中只有 lo 接口,没有 eth0,说明容器没有外部网络连接。

尝试在容器内访问外部网络,例如上面默认 bridge 网络中 container1 可以通过 IP 访问 container2,但在 none 网络下,连最基本的网络请求都无法发出:

docker run --rm --network none my-nginx curl http://www.cnb.com

命令会报错,说明容器完全没有外部网络能力。

Overlay 网络

Overlay 网络是 Docker 用于实现跨主机容器通信的网络驱动,主要用于 Docker Swarm 集群环境。它通过在不同主机的物理网络之上创建虚拟网络,使用 VXLAN 技术在主机间建立隧道,从而实现容器间的透明通信。在 Overlay 网络中,每个容器都会获得一个虚拟 IP,容器之间可以直接通过这个 IP 进行通信,而不需要关心容器具体运行在哪个主机上。

特点:

  • 支持跨主机的容器间通信
  • 基于 VXLAN 隧道技术
  • 支持网络加密,确保跨主机通信的安全性
  • 提供负载均衡和服务发现
  • 适用于微服务架构、分布式应用(如数据库集群、消息队列集群等)

Overlay 网络需要 Docker Swarm 集群环境才能使用,单机环境下无法演示。以下仅展示基本命令供参考。

初始化 Swarm 集群并创建 Overlay 网络:

# 初始化 Swarm(在管理节点上执行) docker swarm init # 创建 Overlay 网络 docker network create --driver overlay my-overlay-network # 查看网络详情 docker network inspect my-overlay-network