四、Docker 网络原理、分类及容器互联配置

本文是《Docker必知必会系列》第四篇,原文发布于个人博客:悟尘纪

上一篇:Docker必知必会系列(三):基于 Docker-registry/Nexus3 搭建本地仓库

Docker 网络配置

Docker 网络基本原理

要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)来收发数据包。如果不同子网之间要进行通信,需要路由机制。

Docker 中的网络接口默认都是虚拟接口,虚拟接口的优势之一是转发效率较高。 Linux 通过在内核中进行数据复制来实现虚拟接口之间的数据转发,发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中。

当 Docker 启动时,会自动在主机上创建一个 docker0 虚拟网桥( Linux 的一个 bridge),它会在挂载到它的网口之间进行转发。同时,Docker 随机分配一个本地未占用的私有网段中的一个地址给 docker0 接口,此后启动的容器内的网口也会自动分配一个同一网段(172.17.0.0/16)的地址。

当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 eth0;另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EuyO1Yaw-1588987217143)(https://pic.lixl.cn/2020/network.png)]

关于 Docker 网络的更多内容,可以访问:https://docs.docker.com/network/>

Docker 网络类型

Docker 创建一个容器的时候,会执行如下操作:

  • 创建一对虚拟接口,分别放到本地主机和新容器中;
  • 本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 veth65f9;
  • 容器一端放到新容器中,并修改名字作为 eth0,这个接口只在容器的命名空间可见;
  • 从网桥可用地址段中获取一个空闲地址分配给容器的 eth0,并配置默认路由到桥接网卡 veth65f9。

完成这些之后,容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络。

可以在 docker run 的时候通过 --net 参数来指定容器的网络配置,有 4 个可选值:

  • --net=bridge 这个是默认值,连接到默认的网桥。
  • --net=host 告诉 Docker 不要将容器网络放到隔离的命名空间中,即不要容器化容器内的网络。此时容器使用本地主机的网络,它拥有完全的本地主机接口访问权限。容器进程可以跟主机其它 root 进程一样可以打开低范围的端口,可以访问本地网络服务比如 D-bus,还可以让容器做一些影响整个主机系统的事情,比如重启主机。因此使用这个选项的时候要非常小心。如果进一步的使用 --privileged=true,容器会被允许直接配置主机的网络堆栈。
  • --net=container:NAME_or_ID 让 Docker 将新建容器的进程放到一个已存在容器的网络栈中,新容器进程有自己的文件系统、进程列表和资源限制,但会和已存在的容器共享 IP 地址和端口等网络资源,两者进程可以直接通过 lo 环回接口通信。
  • --net=none 让 Docker 将新容器放到隔离的网络栈中,但是不进行网络配置。之后,用户可以自己进行配置。

外部访问容器

默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。想要允许外部访问容器,可以在 docker run 时候通过 -p-P 参数来启用(可以多次使用 -p 标记来绑定多个端口)。

使用 docker ps 可以看到,本地主机的 80 被映射到了容器的 80 端口。此时访问本机的 80 端口即可访问容器内 nginx 应用提供的界面。

docker ps
CONTAINER ID  IMAGE   COMMAND        CREATED        STATUS        PORTS               NAMES
bc533791f3f5  nginx   "nginx -g '…"  5 days ago     Up 4 days     0.0.0.0:80->80/tcp  nginx

容器间互联

先创建一个新的 Docker 网络:

docker network create -d bridge lixl-net
  • -d 参数指定 Docker 网络类型,有 bridgeoverlay。其中 overlay 网络类型用于 Swarm mode。

运行一个容器并连接到新建的 lixl-net 网络

docker run -it --rm --name busybox1 --network lixl-net busybox sh

打开新的终端,再运行一个容器并加入到 lixl-net 网络

docker run -it --rm --name busybox2 --network lixl-net busybox sh

再打开一个新的终端查看容器信息

docker ps

CONTAINER ID     IMAGE      COMMAND    CREATED            STATUS         PORTS     NAMES
b47060aca56b     busybox    "sh"       1 minutes ago      Up 1 minutes             busybox2
8720575823ec     busybox    "sh"       1 minutes ago      Up 1 minutes             busybox1

下面通过 ping 来证明 busybox1 容器和 busybox2 容器建立了互联关系。

busybox1 容器输入以下命令

/ # ping busybox2
PING busybox2 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.072 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.118 ms

用 ping 来测试连接 busybox2 容器,它会解析成 172.19.0.3

同理在 busybox2 容器执行 ping busybox1,也会成功连接到。

/ # ping busybox1
PING busybox1 (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.064 ms
64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.143 ms

这样,busybox1 容器和 busybox2 容器建立了互联关系。

如果有多个容器之间需要互相连接,推荐使用 Docker Compose

相关文章

<think>我们已知用户的问题是如何实现不同Docker桥网络下的容器互联。根据引用内容,我们可以总结出两种主要方法: 1. 使用`docker network connect`命令将容器连接到多个网络(推荐) 2. 通过配置路由实现网络互通(高级) 下面我将详细解释这两种方法,并给出步骤。 方法1:容器加入多个网络(推荐) 步骤: 1. 创建两个自定义桥接网络(例如net1和net2) 2. 别在这两个网络中启动容器(例如container1在net1,container2在net2) 3. 将其中一个容器(例如container2)连接到另一个网络(net1) 4. 此时,container1和container2就可以通过容器名互相访问了。 示例命令: ```bash # 创建两个自定义桥接网络 docker network create net1 docker network create net2 # 在net1网络中启动容器container1 docker run -d --name container1 --network net1 nginx # 在net2网络中启动容器container2 docker run -d --name container2 --network net2 nginx # 将container2连接到net1网络 docker network connect net1 container2 # 测试:从container1中ping container2 docker exec -it container1 ping container2 ``` 原理:当container2加入net1后,它会在net1网络中配一个IP地址,这样net1网络中的其他容器(如container1)就可以通过这个IP地址(或容器名)访问container2。同时,container2仍然保留在net2网络中的连接。 方法2:配置网络网关路由(适用于需要网络隔离且不希望容器直接加入对方网络的场景) 步骤: 1. 创建两个自定义桥接网络,并指定子网(例如net1:192.168.1.0/24, net2:192.168.2.0/24) 2. 查看每个网络的网关地址(通过`docker network inspect`) 3. 在宿主机上添加路由规则,将目标网络指向对应网关 4. 开启宿主机IP转发 示例命令: ```bash # 创建两个指定子网的自定义桥接网络 docker network create --driver bridge --subnet 192.168.1.0/24 net1 docker network create --driver bridge --subnet 192.168.2.0/24 net2 # 启动容器别加入这两个网络 docker run -d --name container1 --network net1 nginx docker run -d --name container2 --network net2 nginx # 查看net1网络的网关地址(假设为192.168.1.1) docker network inspect net1 | grep Gateway # 在宿主机上添加路由规则,将net2的流量路由到net1的网关 sudo ip route add 192.168.2.0/24 via 192.168.1.1 # 开启宿主机IP转发(临时生效) sudo sysctl -w net.ipv4.ip_forward=1 ``` 注意:这种方法需要确保宿主机路由配置正确,并且重启后路由规则会丢失,需要持久化配置。另外,这种方法下容器之间不能通过容器名解析,只能通过IP地址访问,因为DNS解析只在同一个网络内有效。 对比: - 方法1简单易行,容器可以通过名称解析,适合大多数场景。 - 方法2需要手动配置路由,容器不能通过名称解析,但可以保持网络隔离(容器不直接加入对方网络),适合有严格网络隔离要求的场景。 根据引用[1]和[2]的内容,推荐使用第一种方法,即通过`docker network connect`命令将容器连接到多个网络,实现互联。 最后,注意:Docker默认的bridge网络(名为bridge)不支持跨网络通信,也不支持容器名称解析,因此建议始终使用自定义网络[^1][^2]。</think>### Docker 不同 Bridge 网络下容器互联实现方法 根据引用内容,实现不同 Bridge 网络容器互联的核心方法是**让容器加入多个网络**(引用[1][2])。以下是详细步骤: #### 方法 1:容器加入多个网络(推荐) ```bash # 1. 创建两个自定义桥接网络 docker network create net1 docker network create net2 # 2. 在不同网络中启动容器 docker run -d --name webapp --network net1 nginx docker run -d --name mysql --network net2 mysql:5.7 # 3. 将mysql容器加入webapp所在的net1网络 docker network connect net1 mysql # 4. 测试互联性(在webapp容器中ping mysql) docker exec -it webapp ping mysql ``` **原理**: 容器加入多个网络后,在每个网络中都有独立 IP 地址和 DNS 解析能力(引用[1])。此时: - `webapp` 可通过 `mysql` 主机名直接访问 - 端口使用容器内部真实端口(如 MySQL 默认 3306),而非映射到宿主机的端口(引用[2]) #### 方法 2:创建共享网络(新建容器时指定) ```bash # 1. 创建共享网络 docker network create --driver bridge \ --subnet 192.168.0.0/24 \ --gateway 192.168.0.1 shared_net # 2. 启动容器时直接加入共享网络 docker run -d --name webapp --network shared_net nginx docker run -d --name mysql --network shared_net mysql:5.7 # 3. 验证互通 docker exec -it webapp ping mysql ``` #### 关键注意事项 1. **必须使用自定义网络**:Docker 默认的 `bridge` 网络不支持跨网络 DNS 解析(引用[3]) 2. **端口使用规则**: - 容器间通信使用服务**内部端口**(如 MySQL 的 3306) - 外部访问才用 `-p` 映射的端口(引用[2]) 3. **网络检查命令**: ```bash docker network ls # 查看网络列表 docker network inspect shared_net # 查看网络详情(含容器IP) ``` 4. **隔离性**:未共享网络的容器无法互通,保持网络隔离(引用[4]) > ⚠️ **重要提示**:跨网络通信必须通过 `docker network connect` 显式连接(引用[1]),Docker 不会自动桥接不同网络。 --- ### 操作示例 假设需要连接 web 应用和 MySQL: ```bash # 创建共享网络 docker network create app_network # 启动MySQL(加入共享网络) docker run --name mysql_db -e MYSQL_ROOT_PASSWORD=pass \ --network app_network -d mysql:5.7 # 启动Web应用(加入同一网络) docker run --name webapp --network app_network -d my_web_image # 在webapp容器内连接数据库 docker exec -it webapp curl http://mysql_db:3306 ``` 此时在 Web 应用中可直接使用 `mysql_db:3306` 作为数据库地址(引用[2])。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值