Docker 服务之间是如何通信的呢?指定服务端口的背后隐藏了哪些秘密?带你揭秘 Docker 网络的神秘面纱!

Posted 魏小言

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker 服务之间是如何通信的呢?指定服务端口的背后隐藏了哪些秘密?带你揭秘 Docker 网络的神秘面纱!相关的知识,希望对你有一定的参考价值。

Docker 指定服务端口的背后隐藏了哪些秘密?带你揭秘 Docker 网络的神秘面纱!

  为什么要聊这个话题呢?
  最近上线关于,“ 广告本地日志分流 ” 新服务,服务模块将以 Docker 「 Docker - Composer 」+ k8s 模型部署。
  上线部署测试时,对 Dockerfile 中 EXPOSE 指令的增加产生了些许思考,这里以此为契机总结梳理下,分享给需要的人,揭开 Docker 网络通信的面纱!

EXPOSE 指令有什么用?

  EXPOSE 顾名思义,声明 Docker 对外暴露的端口号,其它主机或服务可以通过此端口访问 Docker 容器,获得服务。

  • 注意了,EXPOSE 在 Dockerfile 中定义声明 ,而指令是否有效执行,是在 Docker Run 阶段!而在 Run 阶段是否执行生效,和 -P 指令有关!

  • 注意了,是 -P「大写」!而 -P 指令是否执行和 Docker 的网络模型有关!

  是不是已经绕晕了?
  不要慌,你先明确这个:

  • EXPOSE 和 Docker 对外通信有关,但不一定执行生效!与 Docker 网络模型有关。
    • <换句话说就是>
  • Docker 的网络模型决定了其对外通信的方式!

Docker 四种基本网络模型

  Docker 支持四种基本的网络模型:bridge模式、host模式、none模式、其他容器模式;除这四种基本的之外,还支持各种自定义模型。

  网络模型决定了 Docker 容器的通信方式。
  Docker 容器间通信方式可以统分为两种,单机「宿主机内容器间通信」 + 多机「宿主机容器与其它节点服务通信」。

  <上面的 EXPOSE 指令,针对的是 “多机” 模式下的通信,也是实际生产中最常见的模式>

  下面详细唠唠这几种网络模型!

Bridge 模式

  Bridge 模式会为容器创建独立的网络 namespace ,拥有独立的网卡等网格栈。
  基本网络结构,如下:

  <注意:看图之前,你要了解,在 Docker 安装的时候,会自动添加一 Docker 使用的网桥 - docker0 >

  从上面的网络模型可以看出,容器是可以与宿主机乃至外界的其他机器通信的,但是需要额外的配置!
  同一宿主机上,Bridge 模式创建的容器会通过 DHCP 链接到 docker0 上,通过 docker0 实现网络的互通。「容器之间都是连接掉docker0这个网桥上的,它作为虚拟交换机使容器可以相互通信」
  但是,宿主机的 IP 地址与容器 veth pair 的 IP 地址不在同一个网段,宿主机外的网络无法主动发现容器的存在,不能直接进行容器通信。所以 Docker 提供了端口映射的方式,就是将宿主机上的端口流量映射转发到容器内的端口上。

  举一个简单的例子,在 Docker Run 时使用「-p / P 」标记创建容器,将宿主机的 8300 端口绑定到容器的 8300 端口:

docker run -tid —name nginx -p 8300:8300 nginx:latest

-P 标记

  当使用 -P 标记时,Docker 会随机映射一个端口到内部容器开放的网络端口。

EXPOSE 指令

  EXPOSE 指令在 Bridge 模式下,-P 标记时,可将指定的端口随机映射到内部容器端口。

  举个例子,使用 EXPOSE 指定容器端口 9999,启动一个容器:

docker run -P -d nginx:latest

  运行起来之后,就会把容器的 9999 端口映射到宿主机的 32776 端口「随机对外端口」。

-p 标记

  当使用 -p 标记时,则可以指定要映射的IP和端口,但是在一个指定端口上只可以绑定一个容器。
  支持下面几种格式:

ip:hostport:containerport #指定ip、指定宿主机port、指定容器port
ip::containerport #指定ip、未指定宿主机port(随机)、指定容器port
hostport:containerport #未指定ip、指定宿主机port、指定容器port

  举个例子,启动一个容器:

docker run -p 80:80 -v /data:/data -d nginx:latest

  运行起来之后,将容器的 80 端口映射到主机的 80 端口。

注意:Bridge 模式 为 Docker 创建默认模式「 docker run启动容器的时候,如果不加–net参数,就默认采用这种网络模式」。

Host 模式

  Host 模式,host 即本地,容器与宿主机共用网络 namespace,没有独立的网络。
  网络结构图,如下:

  Host 模式下,容器与宿主机所属同一个网络,可以使用宿主机的 IP 地址通信。

  • 对外可通过宿主机公有 IP 进行通信;
  • 对内可直接用宿主机端口进行通信;

  与 Bridge 模式对比,Host 模式通信时数据包还不需要在 Bridge 中转发或 NAT 转换,效率、性能相对优秀!

None 模式

  None 模式,none ,即啥都没有。不会为容器建立任何网络相关配置,需要用户 DIY 配置进行。
  由于是 DIY ,这里不做过多介绍。

Container 模式

  Container 模式,container ,即存在共享关系。这个模式理解的时候,可以与 Host 模式做类比。Host 模式是与宿主机进行共享网络,而 Container 模式是与指定的容器共享网络结构。

  在这个模式下的容器,会使用其他容器的网络命名空间,其网络隔离性会处于bridge桥接模式与host模式之间!

  网络结构图如下:

  Container 模式下的容器可以通过localhost与同一网络命名空间下的其他容器通信,传输效率较高。而且这种模式还节约了一定数量的网络资源,但它并没有改变容器与外界通信的方式。
  在一些特殊的场景中非常有用。例如,kubernetes 的 pod,kubernetes 为pod 创建一个基础设施容器,同一 pod 下的其他容器都以其他容器模式共享这个基础设施容器的网络命名空间,相互之间以 localhost 访问,构成一个统一的整体等等。

网络配置名词解释

  上述是 Docker 基础的几种网络结构,里面涉及到了部分 Linux 内核网络配置的相关知识点,下面简单的做些解释。

eth0

  eth0 物理网卡是指服务器上实际的网络接口设备。设备用于接收以太网数据接口,数据包在各个节点中转发和路由。

veth

  veth 顾名思义,veth-pair 是一对的虚拟设备接口,它都是成对出现的。
  一端连着协议栈,一端彼此相连着。一个设备从协议栈读取数据后,会将数据发送到另一个设备上去。

  正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备,典型的例子像“两个 namespace 之间的连接”,“Bridge、OVS 之间的连接”,“Docker 容器之间的连接” 等等,以此构建出非常复杂的虚拟网络结构,比如 OpenStack Neutron。

bridge

  Bridge 设备是一种纯软件实现的虚拟交换机,可以实现交换机的二层转发。与现实世界中的交换机功能相似。与其他虚拟网络设备一样,可以配置 IP、MAC。Bridge 的主要功能是在多个接入 Bridge 的网络接口间转发数据包。

EXPOSE + Host 模式用法

  梳理了那么多纯网络结构,下面回归正题!
  EXPOSE 除了上文中说的 Bridge 模式中配合 -P 使用,也可以配合 Host 模式使用!

  在 Host 模式下,容器和宿主机共享网络结构,指定 EXPOSE 端口即为使用宿主机的实际端口,这样不用在 Docker Run 阶段指定 - P 标记,同时可以完成宿主机和容器端口的一一对应,这样的维护方式与传统的服务器及其相似,可辨识性高,易上手!
  当然也会有不足,比如宿主机的端口被EXPOSE固定,无法实现真正的容器隔离….等等

Q&A

1、每个模式都不同,都适应什么场景使用呢?

文章中介绍了各自模式的网络架构、优缺点「缺点相对提的少」、大家可通过对比选择适合的。
详细的各自使用场景可关注后续文章!

2、具体在 Docker 环境中是怎么配置这些网络结构呢?

可在 Dockerfile、docker-compose.yml 中分别指定网络模型和端口映射

附录

别人看重的大都是结果,而自己更需要注重过程!

以上是关于Docker 服务之间是如何通信的呢?指定服务端口的背后隐藏了哪些秘密?带你揭秘 Docker 网络的神秘面纱!的主要内容,如果未能解决你的问题,请参考以下文章

Docker 服务之间是如何通信的呢?指定服务端口的背后隐藏了哪些秘密?带你揭秘 Docker 网络的神秘面纱!

Docker网络基础配置

如何通过“主机名”在 Docker 容器之间进行通信

【swarm】Docker跨主机网络:overlay

SOCKET通信 客户端如何指定端口?

Docker ❀ 容器内部/外部通信端口映射网络模式自定义容器网络