当前位置: 首页 > news >正文

docker 网络-用户定义网络

如果你的dokcer版本更新到1.10+,你会发现docker cli中的管理命令中多出一个选项: network Manage networks

Management Commands:builder     Manage buildsbuildx*     Docker Buildxcompose*    Docker Composecontainer   Manage containerscontext     Manage contextsimage       Manage imagesmanifest    Manage Docker image manifests and manifest listsnetwork     Manage networksplugin      Manage pluginssystem      Manage Dockertrust       Manage trust on Docker imagesvolume      Manage volumes

使用Help查看下命令的使用方式

[root@package image]# docker network --help 
Usage:  docker network COMMANDManage networksCommands:connect     Connect a container to a networkcreate      Create a networkdisconnect  Disconnect a container from a networkinspect     Display detailed information on one or more networksls          List networksprune       Remove all unused networksrm          Remove one or more networksRun 'docker network COMMAND --help' for more information on a command.

docker network ls

[root@package image]# docker network ls
NETWORK ID     NAME            DRIVER    SCOPE
0d04f5291ccc   bridge          bridge    local
9c5758e54af4   host            host      local
384c4cfdaf03   none            null      local

默认情况下,基础 Docker 安装已定义这三个网络。这些网络是永久的,无法修改。仔细观察,您可能会注意到这些预定义网络与我们在早期 Docker 版本中使用的网络模型相同。您可以默认以桥接模式启动容器,也可以指定“–net=host”以主机模式启动容器,还可以指定“–net=none”以不使用网络接口启动容器。简而言之,之前的所有网络设置都保留了下来。为了确保一切仍然按预期运行,让我们在每种网络类型下构建一个容器。

Host mode主机模式

docker run -d --name web1 --net=host nginx:stable-alpine3.21

执行上述命令将启动一个测试 nginx Web 服务器,容器的网络堆栈将直接映射到主机的网络堆栈。容器运行后,我们应该能够通过 Docker 主机的 IP 地址访问 Web 服务器…

注意:您需要在 Docker 主机上禁用防火墙或添加适当的规则才能使其正常工作

Bridge Mode 桥接模式

docker run -d --name web1 -p 8081:80 nginx:stable-alpine3.21
docker run -d --name web2 -p 8082:80 nginx:stable-alpine3.21

这里我们运行默认的桥接模式,并将端口映射到容器中。运行这两个容器应该会在端口 8081 和 8082 上显示所需的 Web 服务器……

此外,如果我们直接连接到容器,我们可以看到两个容器之间的通信直接通过 docker0 网桥进行
![[Pasted image 20250527195505.png]]

这里我们可以看到 web1 上有一个 web2 的 APR 条目。查看 Web2 的 MAC 地址,我们发现两者完全相同……
在这里插入图片描述

None mode 无网络模式

docker run -d --name web1 --net=none nginx:stable-alpine3.21

在这个例子中,我们可以看到容器根本没有接收任何接口……

[root@package image]# docker exec -it web1 /bin/sh
/ # ifconfig
lo        Link encap:Local Loopback  inet addr:127.0.0.1  Mask:255.0.0.0inet6 addr: ::1/128 Scope:HostUP LOOPBACK RUNNING  MTU:65536  Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

如你所见,这三种模式的工作方式与 Docker 早期版本中的一样。既然我们已经介绍了现有的网络功能,现在让我们来谈谈新的用户定义网络……

User defined bridge networks 用户定义的桥接网络

最容易使用的用户自定义网络是网桥。定义一个新的网桥非常简单。这里有一个简单的例子……

docker network create --driver=bridge --subnet=192.168.127.0/24 --gateway=192.168.127.1 --ip-range=192.168.127.128/25 testbridge

网关 – 在本例中,我将其设置为 192.168.127.1,这将是 Docker 主机上创建的网桥的 IP 地址。我们可以通过查看 Docker 主机接口来查看……

[root@package ~]# docker network ls
NETWORK ID     NAME            DRIVER    SCOPE
358bb3bf4fb1   bridge          bridge    local
bde3f7cf4b93   host            host      local
c67ef592c63e   none            null      local
7a95dd37854b   testbridge      bridge    local[root@package ~]# ifconfig 
br-26b47815a863: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255inet6 fe80::42:12ff:fe5e:a49f  prefixlen 64  scopeid 0x20<link>ether 02:42:12:5e:a4:9f  txqueuelen 0  (Ethernet)RX packets 0  bytes 0 (0.0 B)RX errors 0  dropped 0  overruns 0  frame 0TX packets 0  bytes 0 (0.0 B)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0br-7a95dd37854b: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500inet 192.168.127.1  netmask 255.255.255.0  broadcast 192.168.127.255ether 02:42:85:e0:17:8e  txqueuelen 0  (Ethernet)RX packets 1578425  bytes 1405516662 (1.3 GiB)RX errors 0  dropped 0  overruns 0  frame 0TX packets 1128558  bytes 87851971 (83.7 MiB)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

子网 – 我将其指定为 192.168.127.0/24。我们可以在上面的输出中看到,这是与网桥关联的 CIDR。

我们可以通过删除现有容器、删除“testbridge”并稍微重新定义它来使这个例子更有趣……

docker stop web1
docker rm web1docker network rm testbridgedocker network create --driver=bridge --subnet=192.168.127.0/24 --gateway=192.168.127.1 --ip-range=192.168.127.128/25 –-internal testbridge

这里唯一的变化是添加了“—internal”标志。这将阻止来自网桥的任何外部通信。让我们通过像这样定义容器来检查一下……

docker run -d --net=testbridge -p 8081:80 --name web1 nginx:stable-alpine3.21

在该网桥上启动的容器,如果通过主机网络访问将会得到一个不可达的错误
显然,“—internal”标志会阻止连接到网桥的容器与主机外部通信。因此,虽然我们现在可以定义新的网桥并将新生成的容器关联到它们,但这本身并没有什么意义。更有趣的是将现有容器连接到这些新网桥的能力。幸运的是,我们可以使用 docker network 的“connect”和“disconnect”命令在任何已定义的网桥上添加和删除容器。让我们首先将容器 web1 连接到默认的 docker0 网桥(网桥)……

docker network connect bridge web1

如果我们查看容器的网络配置,可以看到它现在有两个网卡。一个与“bridge”(docker0 网桥)关联,另一个与“testbridge”关联……
在这里插入图片描述

如果我们再次检查,我们会发现我们现在可以再次通过“桥接”接口上的映射端口访问 Web 服务器……
在这里插入图片描述

我们有一台物理主机 (docker1),其网卡名为“ENS0”,位于 IP 地址为 10.20.30.230 的物理网络中。该主机有两个 Linux 网桥,分别名为“bridge”(docker0)和“testbridge”,每个网桥都有各自定义的 IP 地址。我们还有两个容器,一个名为 web1,它同时与两个网桥关联;另一个名为 web2,它只与原生 Docker 网桥关联。
鉴于此图,您可能会认为 web1 和 web2 能够直接相互通信,因为它们连接到同一个网桥。但是,如果您还记得我们之前的帖子,Docker 有一种称为 ICC(容器间通信)模式的机制。当 ICC 设置为 false 时,容器将无法通过 docker0 网桥直接相互通信。

在这个例子中,我将 ICC 模式设置为 false,这意味着除非我们定义链接,否则 web1 无法通过 docker0 网桥与 web2 通信。但是,ICC 模式仅适用于默认网桥 (docker0)。如果我们将两个容器都连接到网桥“testbridge”,它们应该能够通过该网桥直接通信。我们来试试吧……

docker network connect testbridge web2

在这里插入图片描述

那么让我们从容器中尝试一下,看看会发生什么……
在这里插入图片描述

成功了!用户自定义网桥很容易定义,并且能够将容器映射到网桥上。

Container Linking 容器链接

Docker 的 Linking 机制自早期版本就已存在,并且经常被误认为是某种网络功能。实际上,它与网络策略几乎没有关系,尤其是在 Docker 的默认配置中
在默认配置中,Docker 将 ICC 值设置为 true。在此模式下,docker0 网桥上的所有容器都可以在它们指定的任意端口上直接通信。我们之前在网桥模式示例中看到过这种情况,其中 web1 和 web2 能够互相 ping 通。如果我们更改默认配置并禁用 ICC,则会看到不同的结果。例如,如果我们在“/etc/sysconfig/docker”中将 ICC 值更改为“false”,我们会发现上述示例不再有效……
在这里插入图片描述

如果我们希望 web1 能够访问 web2,我们可以将容器“链接”起来。将一个容器链接到另一个容器,可以让容器之间通过容器暴露的端口相互通信。
在这里插入图片描述

上图显示,一旦链接到位,我无法从 web2 ping 通 web1,但我可以通过其暴露的端口访问 web1。在本例中,该端口为 80。因此,禁用 ICC 的链接仅允许链接的容器在其暴露的端口上相互通信。这是将链接利益与网络或安全策略关联的唯一方式。链接提供的另一个功能是名称和服务解析。例如,让我们看看将 web2 链接到 web1 后,web2 上的环境变量……
在这里插入图片描述

除了环境变量之外,您还会注意到 web2 的 hosts 文件已更新,包含 web1 容器的 IP 地址。这意味着我现在可以通过名称而不是 IP 地址访问容器。如您所见,Docker 早期版本中的链接功能已有其用途,并且该功能现在仍然可用。
用户自定义网络提供了一种非常巧妙的链接替代方案。让我们回到上面的例子,web1 和 web2 通过“testbridge”网桥进行通信。目前,我们还没有定义任何链接,但让我们尝试从 web1 通过名称 ping web2……
在这里插入图片描述

好的,这很酷,但它是如何工作的呢?让我们检查一下容器上的环境变量和 hosts 文件……
在这里插入图片描述

这里根本没有任何内容可以将名称 web2 静态映射到 IP 地址。那么它是如何工作的呢?Docker 现在拥有一个内置的 DNS 服务器。容器名称现在已在 Docker 守护进程中注册,并且可以被同一主机上的任何其他容器解析。但是,此功能仅适用于用户定义的网络。您会注意到,上面的 ping 命令返回的是与“testbridge”关联的 IP 地址,而不是默认的 docker0 网桥。
这意味着我不再需要静态地将容器链接在一起,以便它们能够通过名称进行通信。除了这种自动行为之外,您还可以在用户定义的网络上定义全局别名和链接。例如,现在尝试运行这两个命令……

docker network disconnect testbridge web1
docker network connect --alias=thebestserver --link=web2:webtwo testbridge web1

上面我们从“testbridge”中删除了 web1,然后重新添加它并指定了链接和别名。当将链接标志与用户定义网络一起使用时,其功能与传统链接方法中的功能大致相同。Web1 将能够通过容器名称或其链接别名“webtwo”来解析容器 web2。此外,用户定义网络还提供所谓的“网络范围别名”。这些别名可以由用户定义网段上的任何容器解析。因此,链接由希望使用该链接的容器定义,而别名由发布该别名的容器定义。让我们登录到每个容器并尝试通过链接和别名进行 ping 操作……
在这里插入图片描述

User defined overlay networks 用户定义的覆盖网络

第二种也是最后一种内置用户定义网络类型是覆盖网络 (Overlay)。与桥接网络不同,覆盖网络需要外部键值存储来存储网络、端点、IP 地址和发现信息等信息。在大多数示例中,该键值存储通常是 Consul,但也可以是 Etcd 或 ZooKeeper。那么,让我们来看看本例中要使用的实验……

在这里插入图片描述

这里我们有 3 个 Docker 主机。Docker1 和 docker2 位于 10.20.30.0/24 上,docker3 位于 192.168.30.0/24 上。所有主机都从零开始,定义了 docker0 网桥,但没有运行其他用户定义的网络或容器。
我们要做的第一件事是告诉所有 Docker 主机在哪里找到键值存储。这可以通过编辑“/etc/sysconfig/docker”中的 Docker 配置设置并添加一些选项标志来完成。就我而言,我的“OPTIONS”现在如下所示……

OPTIONS='-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=consul://10.20.30.230:8500/network --cluster-advertise=ens18:2375'

确保调整选项以涵盖运行 Consul 的 Docker 主机的 IP 地址以及“cluster-advertise”标志下定义的接口名称。请在所有加入集群的主机上更新这些选项,然后重启 Docker 服务。
Docker 恢复运行后,我们需要部署前面提到的键值存储,供覆盖驱动程序使用。幸运的是,Consul 以容器的形式提供服务。那么,让我们在 docker1 上部署这个容器……

docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap

一旦 Consul 容器运行起来,我们就可以开始定义覆盖网络了。让我们转到 docker3 主机并定义一个覆盖网络……

docker network create -d overlay --subnet=10.10.10.0/24 testoverlay

现在,如果我们查看 docker1 或 docker2,我们应该看到新定义的覆盖……
在这里插入图片描述

完美,一切按预期进行。现在我们在主机 docker3 上运行一个 Web 容器……
注意:与网桥不同,覆盖网络不会在 Docker 主机上预先创建所需的接口,直到容器使用它们为止。如果您在创建网络时没有看到这些接口生成,请不要感到惊讶。

docker run -d --net=testoverlay -p 8081:80 --name web1 jonlangemak/docker:webinstance1

让我们在 docker2 上启动同一个容器,看看我们得到了什么……
在这里插入图片描述

所以看起来,跨用户自定义覆盖层的容器名称不可能通用。这很合理,所以我们改为加载此主机上的第二个 Web 实例……

docker run -d --net=testoverlay -p 8082:80 --name web2 jonlangemak/docker:webinstance2

一旦此容器运行,让我们通过从 web2 ping web1 来测试覆盖…
![[Pasted image 20250528100942.png]]

很酷。如果我们观察 docker2 和 docker3 之间的物理网络,我们实际上会看到 VXLAN 封装的数据包在两个物理 docker 主机之间传输……

在这里插入图片描述

需要注意的是,覆盖网络本身并没有关联的网桥。但是,每台主机上都定义了一个网桥,用于将物理主机的端口映射到覆盖网络中的容器。例如,让我们看看主机 docker3 上定义的接口……
在这里插入图片描述

注意,这里定义了一个“docker_gwbridge”网桥。如果我们查看容器本身的接口,我们会发现它也有两个接口……
Eth0 是覆盖网络的成员,而 eth1 是我们在主机上看到的网关桥的成员。如果您需要从覆盖网络上的容器公开端口,则需要使用“docker_gwbridge”桥。但是,与用户定义的桥非常相似,您可以在网络创建期间指定“—internal”标志来阻止外部访问。这将阻止容器接收与网关桥关联的额外接口。但这不会阻止在主机上创建“docker_gwbridge”。
由于我们的最后一个例子将使用内部覆盖,让我们删除 web1 和 web2 容器以及覆盖网络,并使用内部标志重建覆盖网络……

#Docker2
docker stop web2
docker rm web2#Docker3
docker stop web1
docker rm web1
docker network rm testoverlay
docker network create -d overlay --internal --subnet=10.10.10.0/24 internaloverlay
docker run -d --net=internaloverlay --name web1 jonlangemak/docker:webinstance1#Docker 2
docker run -d --net=internaloverlay --name web2 jonlangemak/docker:webinstance2

现在我们有两个容器,每个容器在覆盖网络上都有一个接口。让我们确保它们可以相互通信……
在这里插入图片描述

完美,叠加层正常工作了。所以现在——我们的图表看起来就像这样……
![[Pasted image 20250528101321.png]]

目前看来,情况并不乐观,尤其是考虑到我们无法从外部访问这两个容器上运行的 Web 服务器。为了解决这个问题,我们可以在 docker1 上部署一个负载均衡器。为此,我们将使用 HAProxy,因此第一步是创建一个配置文件。我使用的示例如下所示……

globallog 127.0.0.1   local0log 127.0.0.1   local1 noticedefaultslog     globalmode    httpoption  httplogoption  dontlognulloption forwardforoption http-server-closetimeout connect 5000timeout client 50000timeout server 50000stats enablestats auth user:passwordstats uri /haproxyStatsfrontend allbind *:80use_backend webservicebackend webservicebalance roundrobinoption httpcloseoption forwardforserver web1 web1:80 checkserver web2 web2:80 checkoption httpchk HEAD /index.html HTTP/1.0

为了进行此测试,我们只需关注后端部分,它定义了两个服务器。一个名为 web1,可通过 web1:80 地址访问;另一个名为 web2,可通过 web2:80 地址访问。将此配置文件保存到主机 docker1 上,在本例中,我将其保存在“/root/haproxy/haproxy.cfg”中。然后,我们只需使用以下语法启动容器即可……

docker run -d --net=internaloverlay --name haproxy -p 80:80 -v ~/haproxy:/usr/local/etc/haproxy/ haproxy

这个容器启动后,我们的拓扑现在看起来更像这样
在这里插入图片描述

因此,虽然 HAProxy 容器现在可以与两个后端服务器通信,但我们仍然无法在前端与其通信。如果您还记得的话,我们将覆盖网络定义为内部网络,因此我们需要找到另一种访问前端的方法。这可以通过使用网络连接命令将 HAProxy 容器连接到原生 docker0 网桥轻松实现……

docker network connect bridge haproxy

完成后,您应该能够通过访问 docker1 主机的端口 80 来访问 HAProxy 容器的前端,因为这是我们公开的端口
如果运气好的话,你应该会看到 HAProxy 节点在两个 Web 服务器容器之间负载均衡请求。注意,这也可以通过将覆盖网络保留为外部网络来实现。在这种情况下,我们为 HAProxy 容器进行的 80 端口映射将通过“docker_gwbridge”网桥公开,我们无需在容器中添加第二个网桥接口。我这样做只是为了向你展示你还有其他选择。

原英文链接: https://www.dasblinkenlichten.com/docker-networking-101-user-defined-networks/

相关文章:

  • Vue内置指令与自定义指令
  • 深入理解SQLMesh中的Lookback、Forward-Only和Auto-Restatement特性
  • IBM DB2和MYSQL在安全性、稳定性等方面的差异
  • linux中基础IO(上)
  • 【halcon】像素维度:插值算法对图片的影响
  • linux打印项目文件夹结构的命令
  • 【机器学习基础】机器学习入门核心算法:朴素贝叶斯(Naive Bayes)
  • [CARLA系列--03]如何打包生成CARLA 0.9.15的非编辑版(地图的加载与卸载)
  • Docker-compose 编排lnmp(dockerfile) 完成Wordpress
  • 【AI学习笔记】Coze平台实现生成小红书热门多图笔记
  • 【Pandas】pandas DataFrame drop
  • 九、【前后端联调篇】Vue3 + Axios 异步通信实战
  • 探索C++标准模板库(STL):String接口实践+底层的模拟实现(中篇)
  • GitHub 趋势日报 (2025年05月27日)
  • Linux中基础IO(下)
  • Flink CEP实践总结:使用方法、常见报错、优化与难点应对
  • 【Redis】基本架构
  • java导入excel
  • Android-Room + WorkManager学习总结
  • Python生成ppt(python-pptx)N问N答(如何绘制一个没有背景的矩形框;如何绘制一个没有背景的矩形框)
  • 一流设计网站/百度竞价推广价格
  • 做电商网站要备案吗/客户营销
  • 建设部网站工程设计收费标准/百度云在线登录
  • 电子商务网站建设实验总结/国际局势最新消息今天
  • 学校网站建设会议讲话稿/怎样做公司网站推广
  • 贵阳网站建设是什么/网络营销推广方式有哪些