百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

一篇搞定docker网络(docker的网络模式有哪些)

nanshan 2024-10-30 02:54 13 浏览 0 评论

1. Docker 网络理论

容器网络实质上是由 Dokcer 为应用程序所创造的虚拟环境的一部分,它能让应用从宿主机操作系统的网络环境中独立出来,形成容器自有的网络设备、IP 协议栈、端口套接字、IP 路由表、防火墙等等与网络相关的模块。

Docker 为实现容器网络,主要采用的架构由三部分组成:CNM、Libnetwork 和驱动。

1.1. CNM

Docker 网络架构采用的设计规范是 CNM(Container Network Model):CNM 中规定了 Docker 网络的基础组成要素:Sandbox、Endpoint、Network。如图所示,

  • Sandbox,提供了容器的虚拟网络栈,也即端口套接字、IP 路由表、防火墙、DNS 配置等内容。主要用于隔离容器网络与宿主机网络,形成了完全独立的容器网络环境。
  • Network,Docker 内部的虚拟子网,网络内的参与者相互可见并能够进行通讯。Docker 的虚拟网路和宿主机网络是存在隔离关系的,其目的主要是形成容器间的安全通讯环境。
  • Endpoint,就是虚拟网络的接口,就像普通网络接口一样,Endpoint 的主要职责是负责创建连接。在 CNM 中,终端负责将沙盒连接到网络。个人理解:Endpoint 与常见的网络适配器类似,也就意味着 Endpoint 只能接入某一个网络。因此,如果容器需要接入到多个网络,就需要多个 Endpoint。

如上图所示(我们将图中的三个容器从左到右依次标记为 1、2、3),那么容器 2 有两个 endpoint 并且分别接入 NetworkdA 和 NetworkB。那么容器 1 和容器 2 是可以实现通信的,因为都接入了 NetworkA。但是容器 3 和容器 1,以及容器 2 的两个 Endpoint 之间是不能通信的,除非有三层路由器的支持。

1.2. Libnetwork

Libnetwork 是 CNM 的标准实现。Libnetwork 是开源库,采用 Go 语言编写(跨平台的),也是 Docker 所使用的库,Docker 网络架构的核心代码都在这个库中。Libnetwork 实现了 CNM 中定义的全部三个组件,此外它还实现了本地服务发现、基于 Ingress 的容器负载均衡,以及网络控制层和管理层功能。

1.3. 驱动

如果说 Libnetwork 实现了控制层和管理层功能,那么驱动就负责实现数据层。比如网络的连通性和隔离性是由驱动来处理的。驱动通过实现特定网络类型的方式扩展了 Docker 网络栈,例如桥接网络和覆盖网络。

Docker 内置了若干驱动,通常被称作原生驱动或者本地驱动。比如 Bridge DriverHost DriverOverlay DriverMacLan DriverNone Driver 等等。第三方也可以编写 Docker 网络驱动,这些驱动被叫做远程驱动,例如 Calico、Contiv、Kuryr 以及 Weave 等。每个驱动负责创建其上所有网络资源的创建和管理。

其中 Bridge 和 Overlay 在开发过程中使用频率较高。

  • Bridge,Docker 容器的默认网络驱动,通过网桥来实现网络通讯。
  • Overlay,借助 Docker 集群模块 Docker Swarm 搭建的跨 Docker Daemon 网络。通过它可以搭建跨物理网络主机的虚拟网络,进而让不同物理机中运行的容器感知不到多个物理机的存在。


在 Docker 安装时,会自动安装一块 Docker 网卡称为 docker0,用于 Docker 各容器及宿主机的网络通信。

docker0   Link encap:Ethernet  HWaddr 02:42:be:6b:61:dc
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          inet6 addr: fe80::42:beff:fe6b:61dc/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:332 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:30787 (30.7 KB)

个人理解:CNM 就是一个设计文档,指导你怎么去实现容器网络,而 Libnetwork 和驱动则是其具体实现,从而确保容器网络的通信

2. 桥接网络

Docker 的 bridge 网络采用内置的 bridge 驱动,而 bridge 的底层采用的是 Linux 内核中 Linux bridge 技术(这意味着 bridge 是高性能并且是非常稳定的)。

那么 Linux 内核中 Linux bridge 应用于容器的话,到底是一个什么样的拓扑图呢?如图所示(这个拓扑关系不清楚接下去的很多东西难以理解,所以先贴出采用 bridge 之后的一个拓扑图),由于容器运行在自己单独的 network namespace 中,所以有单独的协议栈。容器中配置网关为 172.17.0.1,发出去的数据包先到达 br0,然后交给主机的协议栈,由于目的 IP 是外网 IP,且主机会开启 IP forward 功能,于是数据包通过主机的 eth0 发出去。由于 172.17.0.1 是内网 IP ,所以一般发出去之前会做 NAT 转换。由于要进过主机的协议栈并且要做 NAT 转换,所以性能上可能会差点,但是优点就是容器处于内网中,安全性相对要高点。

默认情况下,创建的容器在没有使用 --network 参数指定要加入的 docker 网络时,默认都是加入 Docker 默认的单机桥接网络,也就是下面的 name 为 bridge 的网络。

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
0dda6f303b8b        bridge              bridge              local

而默认的 bridge 网络是被映射到内核中为 docker0 的网桥上。

$ ip link show docker0
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
    link/ether 02:**:**:**:**:** brd ff:ff:ff:ff:ff:ff

$ docker network inspect bridge | grep bridge.name
            "com.docker.network.bridge.name": "docker0",

Docker 默认的 bridge 网络和 Linux 内核中的 “docker0” 网桥是一个对应关系,如图所示。bridge 是 Docker 中对网络的命名,而 docker0 是内核中网桥的名字。(个人理解:你就可以把 bridge 和 docker0 当成 Linux 网桥的两个名字,两个都是代表同一个东西。docker 为了管理网络,又给 docker0 这个网桥取名为 bridge)。


那么,容器在没有指定要加入的网络情况下,都是加入这个网络的,假如之后的拓扑图跟前面的一样。另外,单机桥接网络中的容器想要对外发布服务的话,需要依赖于端口映射,这也是为啥我们在启动容器的时候需要指定端口映射关系 的原因。

下面我们通过创建一个新的 Docker 桥接网络来阐述容器内部的通信、端口映射等情况。

2.1. 创建新的单机桥接网络

使用 docker network create 命令,我们可创建一个名为 “localnet” 的单机桥接网络,并且在内核中还会多出一个新的 Linux 网桥。

$ docker network create -d bridge localnet

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
			......
f55943e20201        localnet            bridge              local

在创建完之后,我们可以通过 brctl 工具来查看系统中的 Linux 网桥。可以看到,输出的内容中包含了两个网桥,docker0 是默认的 Docker bridge 网络所使用的网桥,br-f55943e20201 是 Docker localnet 网络所使用的网桥。这两个网桥目前都没有任何设备接入(看 interface 列)。这两个网桥所处的网段是不同的,一个是 172.18.0.1,另一个则是 172.17.0.1。

$ brctl show
bridge name     bridge id               STP enabled     interfaces
br-f55943e20201 8000.02421d9aa3e1       no
docker0         8000.0242be6b61dc       no

$ ifconfig
br-f55943e20201 Link encap:Ethernet  HWaddr 02:42:1d:9a:a3:e1
          inet addr:172.18.0.1  Bcast:172.18.255.255  Mask:255.255.0.0
			......
docker0   Link encap:Ethernet  HWaddr 02:42:be:6b:61:dc
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
			......

2.2. 同个网络中的容器间通信

使用下面这条命令即可运行一个新的容器,并且让这个新容器加入到 localnet 这个网络中的。

$ docker container run -d --name demo1 --network localnet alpine sleep 3600

我们查看网桥的情况,demo1 的网络接口连接到了网桥 br-f55943e20201 上,如图所示。

$ brctl show
bridge name     bridge id               STP enabled     interfaces
br-f55943e20201 8000.02421d9aa3e1       no              vethf6a3fba
docker0         8000.0242be6b61dc       no

如果在相同的网络中继续接入新的容器,那么新接入的容器是可以通过 demo1 这个名称来 ping 通的。如下所示,我们创建了一个新的容器(demo2),并且在这个容器中直接 ping demo1 发现可以的 ping 通的。这是因为,demo2 运行了一个本地 DNS 解析器,该解析器会将该请求转发到 Docker 内部 DNS 服务器中。DNS 服务器中记录了容器启动时通过 --name 或者 --net-alias 参数指定的名称和容器之间的和映射关系。

之外,我们可以看到 demo1 的 IP 地址是 172.18.0.2,这个与网桥 br-f55943e20201 是处于同一个网段内的。

/ # ls
bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var
/ # ping demo1
PING demo1 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.230 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.161 ms

Docker 默认的 bridge 网络是不支持通过 Docker DNS 服务进行域名解析的,自定义桥接网络是可以的。

2.3. 暴露端口

同一个网络中的容器之间虽然可以互相 ping 通,但是并不意味着可以任意访问容器中的任何服务。Docker 为容器增加了一套安全机制,只有容器自身允许的端口,才能被其他容器所访问。如下所示,我们可以通过 docker container ls 命令可以看到容器暴露给其他容器访问的端口是 80,那么我们只能容器的 80 端口进行访问,而不能对没有开放的 22 端口进行访问。

$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
5a8dece3841d        nginx               "/docker-entrypoint.…"   3 minutes ago       Up 3 minutes        80/tcp              web

$ telnet 172.18.0.2 80
Trying 172.18.0.2...
Connected to 172.18.0.2.
Escape character is '^]'.

$ telnet 172.18.0.2 20
Trying 172.18.0.2...
telnet: Unable to connect to remote host: Connection refused

我们可以在镜像创建的时候定义要暴露的端口,也可以在容器创建时定义要暴露的端口,使用 --expose。如下所示,就额外暴露了 20、22 这两个端口。

$ docker container run -d --name web --expose 22 --expose 20 nginx

$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
4749dac32711        nginx               "/docker-entrypoint.…"   12 seconds ago      Up 10 seconds       20/tcp, 22/tcp, 80/tcp   web

容器的端口暴露类似于打开了容器的防火墙,具体能不能通过这个端口访问容器中的服务,还得看容器中有无应用监听并处理来自这个端口的请求。

2.4. 端口映射

上面提到的桥接网络中的容器只能与位于相同网络中的容器进行通信,假如一个容器想对外提供服务的话,需要进行端口映射。端口映射将容器的某个端口映射到 Docker 主机端口上。那么任何发送到该端口的流量,都会被转发到容器中。如图所示,容器内部开放端口为 80,该端口被映射到了 Docker 主机的 10.0.0.15 的 5000 端口上。最终访问 10.0.0.15:5000 的所有流量都会被转发到容器的 80 端口。

如下图所示,假设我们运行了一个新的 web 服务容器,并且将容器 80 端口映射到 Dokcer 主机的 5000 端口。

$ docker container run -d --name web --network localnet -p 5000:80 nginx

那么,当我们通过 web 浏览器访问 Docker 主机的 5000 端口时,会得到如图所示的结果。外部系统可以通过访问 Docker 主机的 TCP 端口 5000,来访问运行在桥接网络上的 Nginx 容器了。

端口映射之后,假如主机的 5000 端口被占用了,那么其他容器就不能再使用这个端口了。


3. 相关命令

# 列出运行在本地 docker 主机上的全部网络
docker network ls

# 提供 Docker 网络的详细配置信息
docker network inspect <NETWORK_NAME>

# 创建新的单机桥接网络,名为 localnet,其中 -d 不指定的话,默认是 bridge 驱动。并且主机内核中也会创建一个新的网桥。
docker network create -d bridge localnet

# 删除 Docker 主机上指定的网络
docker network rm

# 删除主机上全部未使用的网络
docker network prune

# 运行一个新的容器,并且让这个容器加入 Docker 的 localnet 这个网络中
docker container run -d --name demo1 --network localnet alpine sleep 3600

# 运行一个新的容器,并且让这个容器暴露 22、20 两个端口
docker container run -d --name web --expose 22 --expose 20 nginx

# 运行一个新的容器,并且将这个容器的 80 端口映射到主机的 5000 端口
docker container run -d --name web --network localnet -p 5000:80 nginx

# 查看系统中的网桥
brctl show

4. 大佬文章

1. https://zhuanlan.zhihu.com/p/57203485

2. https://segmentfault.com/a/1190000009491002

3. http://blog.nsfocus.net/linux-bridge/

相关推荐

Linux 中如何提取压缩文件 ?(linux怎么解压到当前文件夹)

Linux是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在Linux中提取不同类型的压缩文件。1.Unpa...

在 WSL 中体验 Unix 哲学:从发消息到加密传输文件

Unix哲学强调小而简单的工具,利用它们组合起来完成复杂的任务。WindowsSubsystemforLinux(WSL)为我们提供了一个可以在Windows上运行Linux工具的...

还在用数据线?这样传文件简直不要太方便!支持多设备互传!

这是一款局域网文件传输工具,它支持windows端、安卓端、苹果端、和linux端的设备在同一局域网下进行文件互传,省去了数据线连接的麻烦。工具我已经为大家打包好了,有兴趣的朋友可以在这里获取。大家好...

Linux远程文件传输神器:rz / sz 全指南(含实操示例)

原文链接:「链接」在日常使用Linux服务器时,是否常常因为文件传输问题而苦恼?复制粘贴效率低,FTP配置复杂?今天推荐一套简单高效的终端工具组合:rz和sz。这两个命令搭配使用,能在本地与...

机房搬迁后域控服务器失联?原因令人乍舌,看我如何快速修复

一、问题背景:一场搬迁后引发的连锁故障为某客户的主域服务器升级内存,因为我们知道有备域,所以也就没多想,直接关闭了主域服务器,可是刚打开机箱盖,就有用户反馈,不能上网了,紧接着,各部门都来反馈断网,难...

办公室SSH服务器远程访问,重启自动建立通道

背景可以通过一台外网服务器建立来自Internet上的客户与办公室SSH服务的连接。Ubuntu下可以使用如下命令。autossh-M0-o"ServerAliveInterval3...

Windows Autopatch热修复功能上线:企业PC Win11更新无需重启

IT之家6月25日消息,今年5月,微软为Windows11设备发布了首个热修复更新,并在同一时期为WindowsAutopatch添加了热修复功能。Autopatch是微软的...

路由器设置优化指南,小白也能轻松上手!

【ZOL中关村在线原创技巧应用】在数字化时代,网络已成为生活必需品,追剧、游戏、办公、学习都离不开稳定高速的网络。但很多人面对新路由器,不知道如何设置才能上网。本文将用通俗易懂的方式,一步步教你完成设...

如何防止DDoS攻击导致的服务中断(如何防止服务器被ddos)

防止DDoS(分布式拒绝服务)攻击导致的服务中断需要结合多种技术和策略。DDoS是通过大量恶意流量压垮服务器或网络资源,使正常用户无法访问服务。以下是针对DDoS攻击的预防措施和应对策略,帮...

零配置网络与.local 后缀(零配置失败)

在小型的家庭网络或办公室环境中,你可能经常遇到这样的场景:想要访问网络中的一台设备,比如家里的网络打印机、智能音箱,或者一个共享文件服务器,但你不知道它的具体IP地址。每次都要去路由器后台查看或者...

蓝牙无法搜索到设备?全面排查与解决指南

蓝牙作为主流无线连接技术,偶尔会出现“无法搜索到设备”的问题,这类故障多由设备状态、设置错误或兼容性问题引发。以下是一套系统化的排查方案,从基础检查到深度修复,帮你快速恢复蓝牙连接功能。一、快速检...

电脑网络出现黄色感叹号?一文教你彻底解决无网络连接问题

当电脑右下角的网络图标突然亮起黄色感叹号,显示"无Internet连接"时,这种突如其来的断网状况往往让人措手不及。无论是正在进行的视频会议、即将提交的工作文件,还是在线游戏的关键时刻...

手机信号恢复最简单的方法(手机信号怎么修)

重启手机或开关飞行模式信号恢复最简单的方法是重启手机或开关飞行模式,这一操作能快速刷新网络连接,解决80%以上的临时性信号丢失问题。快速恢复信号的简易步骤开关飞行模式。下拉通知栏,开启飞行模式等待10...

《Windows 学习:100 条命令大全》内容总结

一、文件与目录管理1.基础操作dir:用于列出当前目录下的文件和子目录。在命令提示符中输入dir,即可显示当前目录的内容,如文件名称、大小、修改日期等信息。若想查看隐藏文件,可使用dir/a命令。...

路由器亮红灯:网络“健康警报”的全面解读与自救指南

当你发现路由器的指示灯突然泛起红光,往往代表着你的网络连接已出现严重问题。面对这一情况,不必惊慌。本文将带你一步步拆解红灯背后的常见原因,并提供系统性的解决方案,让你从被动等待转为主动修复。红灯亮起的...

取消回复欢迎 发表评论: