前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【重识云原生】第六章容器6.1.12节——Docker网络模型设计

【重识云原生】第六章容器6.1.12节——Docker网络模型设计

作者头像
江中散人_Jun
发布2022-09-28 15:24:06
4160
发布2022-09-28 15:24:06
举报
文章被收录于专栏:云原生布道专栏

1 容器网络背景概述

1.1 Linux的namespace+cgroup

        先来简要回顾一下前面的内容,namespace和cgroup是Linux 内核的两大特性,namespace的诞生据说就是为了支持容器技术,那么这俩特性到底干了啥呢?

         - namespace:linux支持多种类型的namespace,包括Network,IPC,PID, Mount, UTC, User。创建不同类型的namespace就相当于从不同资源维度在主机上作隔离。

         - cgroup:为了不让某个进程一家独大,而其他进程饿死,所以它的作用就是控制各进程分配的CPU,Memory,IO等。

         - namespace+cgroup也适用进程组,即多进程运行在一个单独的ns中,此时该ns下的进程就可以交互了。

参考:Docker基础技术:Linux Namespace(上) | 酷 壳 - CoolShell

1.2 容器

        "容器"这个概念其实是Linux本身就具有的,无非就是对一个"隔离环境"的另一种说法,或者说容器就是结合了namespace 和 cgroup 的一般内核进程,注意,容器就是个进程。

        容器的实现有多种方式,其中Docker公司实现的docker 容器也是目前最为常用的一种容器技术,所以我们接下来就以docker为例,看看他的实现是怎么帮我们创建,管理这样一个个"互相隔离着的进程"。所以,当我们使用Docker起一个容器的时候,Docker会为每一个容器创建属于他自己的namespaces,即各个维度资源都专属这个容器了,此时的容器就是一个孤岛,也可以说是一个独立VM就诞生了。当然他不是VM,网上关于二者的区别和优劣有一对资料.

        更进一步,也可以将多个容器共享一个namespace,比如如果容器共享的是network 类型的namespace,那么这些容器就可以通过 localhost:[端口号]  来通信了。因为此时的两个容器从网络的角度看,和宿主机上的两个内核进程没啥区别。

        容器网络从范围上分:

  • 单机网络:none,host, bridge
  • 跨主机网络:overlay,macvlan,flannel等

        从生成方式分:

  • 原生网络:即利用宿主机操作系统本身就提供的功能构建的网络,包括:none,host, bridge
  • 自定义网络:
    • docker容器实现中自带的网络驱动:bridge(自定义),overlay,macvlan,
    • 使用第三方驱动实现的自定义网络:flannel、Calico等

        在学习网络的时候肯定遇到过关于CNM这个概念,所以首先,我们一起学习下CNM&libnetwork

1.3 CNM&libnetwork

       首先,Docker实现的容器技术中,针对网络这一块他抽象出一个模型来,就叫CNM(Container Networking Model),相当于只实现了一个框架,具体的实现可以使用原生Docker的,也可以自己实现然后接入本框架。其中libnetwork是Docker团队将Docker的网络功能从Docker的核心代码中分离出来形成的一个单独的库,libnetwork通过插件的形式接入CNM为Docker提供网络功能。

        该模型包含三部分:

  • Sandbox:容器的网络栈,包含interface、路由表、DNS设置等,可以看做就是linux network类型的namespace本身,该有的网络方面的东西都要有,另外还包含一些用于连接各种网络的endpoint;
  • Endpoint : 用来将sandbox接入到network中,典型的实现是Veth pair技术(Veth pair是Linux固有的,是一个成对的接口,用来做连接用);
  • Network (框架): 具体的网络实现,比如是brige、VLAN等,同样它包含了很多endpoint(那一头);

      一句话:sandbox代表容器,network代表由网络驱动构建的容器的网络,endpoint代表接入点即他连接了二者。

        CMN模型提供了2个可插拔的接口,让用户可以自己实现驱动然后接入该接口,支持驱动有两类:网络驱动和IPAM驱动,看看这俩类驱动干什么的?

  • Network Drivers: 即真正的网络实现,可以为Docker Engine或其他类型的集群网络同时提供多种驱动,但是每一个具体的网络只能实例化一个网络驱动。细分为本地网络驱动和远端网络驱动:   
    • 本地网络驱动:对应前面说到的原生网络;
    • 远端网络驱动:对应前面说的自定义网络;
  • IPAM Drivers — 构建docker网络的时候,每个docker容器如果不手动指定的话是会被分配ip地址的,这个分配的任务就是由该驱动完成的,同样的,Docker Engine还是给我们提供了缺省的实现。

        整个的原理模型图如下,参见官网:

         参考:https://success.docker.com/article/networking

2 Docker的四种网络模型

2.1 概述

        docker的网络模型分为四种:

  1. Bridge模式,与宿主机共享一个局域网,有自己的网络,用于单个host上多个容器之间通信,是 Docker 的默认网络模式,可以使用 –net=bridge 指定;
  2. Host模式,与宿主机共享一个网络,使用 –net=host 指定;
  3. Container模式,与另一个容器共享一个网络,eg:业务容器和数据库容器,使用 –net=container: 容器名称或ID 指定;
  4. None模式,封闭网络,使用 –net=none 指定,如果使用K8S网络模型,则需设置为此模式。

2.2 Bridge 模式

        Bridge 模式是 Docker 默认使用的网络模式。当Docker server启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。接下来就要为容器分配IP了,Docker会从RFC1918所定义的私有IP网段中,选择一个和宿主机不同的IP地址和子网分配给docker0,连接到docker0的容器就从这个子网中选择一个未占用的IP使用。

        Docker完成以上网络配置的过程大致是这样的:

  1. Docker Daemon 利用 veth pair 技术,在宿主机上创建一对虚拟网卡veth pair设备,假设为veth0 和 veth1。veth设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth设备常用来连接两个网络设备。
  2. Docker Daemon 将 veth0 附加到 Docker Daemon 创建的 docker0 网桥上,保证宿主机的网络报文可以发往 veth0,可以通过brctl show命令查看;
  3. Docker Daemon 将 veth1 添加到 新创建的Docker Container 所属的 namespace 下,并被改名为 eth0。
  4. 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。
  5. 如此一来,保证宿主机的网络报文若发往 veth0,则立即会被 eth0 接收,实现宿主机到Docker Container 网络的联通性;同时,也保证 Docker Container 单独使用 eth0,实现容器网络环境的隔离性。
代码语言:javascript
复制
# 查看本机网络配置

ip addr

...

docker0: mtu 1500 qdisc noqueue state DOWN group default

link/ether 02:42:51:82:92:0a brd ff:ff:ff:ff:ff:ff

inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0

valid_lft forever preferred_lft forever

inet6 fe80::42:51ff:fe82:920a/64 scope link

valid_lft forever preferred_lft forever

...

# 启动一个容器

docker run -dit ubuntu

# 查看网络配置

ip addr

...

vethc51f579@if9: mtu 1500 qdisc noqueue master docker0 state UP group default

link/ether 5e:fd:53:cc:54:58 brd ff:ff:ff:ff:ff:ff link-netnsid 0

inet6 fe80::5cfd:53ff:fecc:5458/64 scope link

valid_lft forever preferred_lft forever

# 进入容器

docker exec -it {{ID}} bash

# 安装 net-tools

apt-get update

apt-get install net-tools

# 查看网络配置

ifconfig

...

eth0: flags=4163 mtu 1500

inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255

ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)

RX packets 2452 bytes 13783808 (13.7 MB)

RX errors 0 dropped 0 overruns 0 frame 0

TX packets 2012 bytes 152399 (152.3 KB)

TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

        通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络:

         bridge 桥接模式下的 Docker Container 在使用时,并非为开发者包办了一切。最明显的是,该模式下 Docker Container 不具有一个公有 IP,即和宿主机的 eth0 不处于同一个网段。导致的结果是宿主机以外的世界不能直接和容器进行通信。虽然 NAT 模式经过中间处理实现了这一点,但是 NAT 模式仍然存在问题与不便,如容器均需要在宿主机上竞争端口,容器内部服务的访问者需要使用服务发现获知服务的外部端口等。另外 NAT 模式由于是在三层网络上的实现手段,故肯定会影响网络的传输效率。

2.3 Host 模式

        Docker 为了实现网络的隔离,使用了 Network Namespace 对网络进行隔离。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的 IP 和端口。

代码语言:javascript
复制
# 查看最开始的网络配置

ip addr

# 以host模式启动一个容器

docker run -dit -p 80:80 --net host nginx

# 查看网络配置

ip addr

# 未发现多出 veth 接口,网络配置与之前没有任何区别

        而外界访问容器中的应用,则直接使用主机IP:80 即可,不用任何NAT转换,就如直接跑在宿主机中一样。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

        host 模式是 bridge 桥接模式很好的补充。采用 host 模式的 Docker Container可以直接使用宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换。当然,有这样的方便,肯定会损失部分其他的特性,最明显的是 Docker Container 网络环境隔离性的弱化,即容器不再拥有隔离、独立的网络栈。另外,使用 host 模式的 Docker Container 虽然可以让容器内部的服务和传统情况无差别、无改造的使用,但是由于网络隔离性的弱化,该容器会与宿主机共享竞争网络栈的使用。另外,容器内部将不再拥有所有的端口资源,原因是部分端口资源已经被宿主机本身的服务占用,还有部分端口已经用以 bridge 网络模式容器的端口映射。

2.4 Container 模式

        Container 模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

代码语言:javascript
复制
# 以默认模式一个容器

docker run -dit --name u1 ubuntu

# 以 container 模式启动另一个容器

docker run -dit --name u2 --network container:u1 ubuntu

# 查看网络配置

ifconfig

# 发现只多了一个 veth

        Docker Container 的 other container 网络模式,可以用来更好的服务于容器间的通信。在这种模式下的 Docker Container可以通过 localhost 来访问 namespace 下的其他容器,传输效率较高。虽然多个容器共享网络环境,但是多个容器形成的整体依然与宿主机以及其他容器形成网络隔离。另外,这种模式还节约了一定数量的网络资源。但是需要注意的是,它并没有改善容器与宿主机以外世界通信的情况。

2.5 None 模式

        此模式下容器不参与网络通信,运行于此类容器中的进程仅能访问本地环回接口,仅适用于进程无须网络通信的场景中,例如备份,进程诊断及各种离线任务等。如果使用K8S网络模型,则需设置为此模式。

代码语言:javascript
复制
# 以 None 模式运行一个容器

docker run -dit --network none ubuntu

# 进入容器查看

ifconfig

# 只有 lo 网卡

lo: flags=73 mtu 65536

inet 127.0.0.1 netmask 255.0.0.0

inet6 ::1 prefixlen 128 scopeid 0x10

loop txqueuelen 1000 (Local Loopback)

RX packets 29 bytes 2569 (2.5 KiB)

RX errors 0 dropped 0 overruns 0 frame 0

TX packets 29 bytes 2569 (2.5 KiB)

TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

        网络环境为 none,即不为 Docker Container 任何的网络环境。一旦 Docker Container 采用了none 网络模式,那么容器内部就只能使用 loopback 网络设备,不会再有其他的网络资源。可以说 none 模式为 Docker Container 做了极少的网络设定,但是俗话说得好“少即是多”,在没有网络配置的情况下,作为 Docker 开发者才能在这基础做其他无限多可能的网络定制开发。这也恰巧体现了 Docker 设计理念的开放。在 none 网络模式下分配固定 ip:netns 是在 linux 中提供网络虚拟化的一个项目,使用 netns 网络空间虚拟化可以在本地虚拟化出多个网络环境。目前 netns 在 lxc 容器中被用来为容器提供网络。使用 netns 创建的网络空间独立于当前系统的网络空间,其中的网络设备以及 iptables 规则等都是独立的,就好像进入了另外一个网络一样。

3 docker 网络初始化过程

参考链接

Docker 四种网络模型_执笔苦行僧的博客-CSDN博客_docker网络模型

docker 网络模型_幽雨雨幽的博客-CSDN博客_docker网络模型

docker网络模型 - 德乌姆列特 - 博客园

(十四)Docker0网络详解_IT_狂奔者的博客-CSDN博客_docker0网卡的作用

Docker的docker0网络 - Kit_L - 博客园

ifconfig 中的 eth0 eth0:1 eth0.1 与 lo - JokerJason - 博客园

docker容器的四种网络模型_xbw_linux123的博客-CSDN博客

Docker容器网络基础 - 水鬼子 - 博客园

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 容器网络背景概述
    • 1.1 Linux的namespace+cgroup
      • 1.2 容器
        • 1.3 CNM&libnetwork
        • 2 Docker的四种网络模型
          • 2.1 概述
            • 2.2 Bridge 模式
              • 2.3 Host 模式
                • 2.4 Container 模式
                  • 2.5 None 模式
                  • 3 docker 网络初始化过程
                  • 参考链接
                  相关产品与服务
                  容器服务
                  腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档