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

魏小言 魏小言     2022-12-19     768

关键词:

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网络的神秘面纱!EXPOSE指令有什么用?Docker四种基本网络模型Bridge模式-P标记EXPOSE指令-p标记Host模式None模式Container模式网络配置名词解释eth0vethbridgeEXPO... 查看详情

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

】如何通过“主机名”在Docker容器之间进行通信【英文标题】:HowtocommunicatebetweenDockercontainersvia"hostname"【发布时间】:2015-08-1305:33:45【问题描述】:我计划将我的单体服务器拆分为许多小型docker容器,但尚未找到“容器... 查看详情

Docker 微服务架构 - 不同容器之间的通信

】Docker微服务架构-不同容器之间的通信【英文标题】:DockerMicroserviceArchitecture-Communicationbetweendifferentcontainers【发布时间】:2018-06-2601:22:35【问题描述】:我刚开始使用docker,目前正在尝试研究如何使用微服务架构设置项目。我... 查看详情

docker——端口映射与容器互联

...器来说,容器之间就需要相互访问。除了网络访问之外,docker还提供了另外两种方式来满足服务的访问。   一:允许映射容器内应用的服务端口到本地宿主机;   二:互联网机制实现多个容器间通过容器名来快速访问;&nbs... 查看详情

service之间如何通信?-每天5分钟玩转docker容器技术(101)

微服务架构的应用由若干service组成。比如有运行httpd的web前端,有提供缓存的memcached,有存放数据的mysql,每一层都是swarm的一个service,每个service运行了若干容器。在这样的架构中,service之间是必然要通信的。服务发现一种实... 查看详情

两个 docker 容器之间的通信问题

】两个docker容器之间的通信问题【英文标题】:Troublecommunicatingbetweentwodockercontainers【发布时间】:2018-07-1503:55:54【问题描述】:我是docker新手,我正在尝试将运行在boot-exampledocker容器中的springboot应用程序连接到运行在mymysql中的... 查看详情

【swarm】docker跨主机网络:overlay

参考技术ADocker早期版本中,是不支持跨主机通信网络驱动的,也就是说明如果容器部署在不同的节点上面,只能通过暴露端口到宿主机上,再通过宿主机之间进行通信。随着dockerswarm集群的推广,docker也有了自家的跨主机通信网... 查看详情

通过 Docker 主机名在两个微服务之间进行通信

】通过Docker主机名在两个微服务之间进行通信【英文标题】:CommunicationbetweentwomicroservicesbyDockerhostname【发布时间】:2018-09-0703:39:42【问题描述】:现在如何运作:微服务X使用静态IP向微服务Y发出RESTAPI请求http://ip-address:port/doSomet... 查看详情

java网络编程:如何实现客户端与客户端之间的之间通信

...通过C1-S-C2这样的间接方式,而是C1-C2。求思路与关键代码服务器告知双方对方的ip地址,并协调由哪一方主动连接。如协调结果是:把c2的地址告诉c1,让c1主动连接c2,让c2打开端口等待连接。要考虑认证问题,比如c2如何知道连... 查看详情

docker基础:网络配置详解

本篇文章将讲述Docker的网络功能,包括使用端口映射机制来将容器内应用服务提供给外部网络,以及通过容器互联系统让多个容器之间进行快捷的网络通信,有兴趣的可以了解下。 大量的互联网应用服务包含多个服务组件,... 查看详情

在 docker-compose 中的两个 docker 服务之间进行通信

】在docker-compose中的两个docker服务之间进行通信【英文标题】:Communicatingbetweentwodockerservicesindocker-compose【发布时间】:2020-09-0401:50:36【问题描述】:我刚开始使用docker-compose并被困在两个服务之间的通信中。我有2个服务:angular... 查看详情

docker容器之间的通信(代码片段)

前言平常在使用Docker容器部署项目的时,比如我们构建一个SpringBoot项目的容器和一个Redis的容器,我们希望SpringBoot项目可以正常访问到Redis容器,通常做法是这样的:假如我们的服务器公网IP地址是178.78.7.8,... 查看详情

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

...口,比如在0和30000之间这个可以实现吗?用JAVA,谢谢和服务器绑定端口一样,只是一般客户端不需要绑定端口。java应该也可以structsockaddr_inclientAddr;clientAddr.sin_family=AF_INET;clientAddr.sin_port=htons(6666);clientAddr.sin_addr.S_un.S_addr=0;bind(sock... 查看详情

使用 docker-compose 和 traefik 实现微服务之间的通信

】使用docker-compose和traefik实现微服务之间的通信【英文标题】:Communicationbetweenmicroserviceswithdocker-composeandtraefik【发布时间】:2019-07-1219:41:21【问题描述】:我有一个基于微服务的节点应用程序。我正在使用docker、docker-compose和tra... 查看详情

什么是socket?简述基于tcp协议的套接字通信流程?

...同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。 基于tcp协议的套接字通信流程:1).服务器先用socket函... 查看详情

docker容器之间的通信(代码片段)

前言平常在使用Docker容器部署项目的时,比如我们构建一个SpringBoot项目的容器和一个Redis的容器,我们希望SpringBoot项目可以正常访问到Redis容器,通常做法是这样的:假如我们的服务器公网IP地址是178.78.7.8,... 查看详情

创建端口并启动客户端和服务器之间的通信

】创建端口并启动客户端和服务器之间的通信【英文标题】:creatingportsandinitiatingcommunicationbetweenclientandserver【发布时间】:2010-07-2408:12:56【问题描述】:我需要的是一个监听5060端口的服务器,当客户端向该端口发送数据时,服... 查看详情

11、docker的网络功能-配置容器网桥

参考技术ADocker服务默认会创建一个名称为docker0的Linux网桥(其上有一个docker0内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。用户使用Docker创建多个自定义网络时可能... 查看详情