1、CNM

CNM (Container Network Model) 是 Docker 发布的容器网络标准,意在规范和指定容器网络发展标准,CNM 抽象了容器的网络接口 ,使得只要满足 CNM 接口的网络方案都可以接入到 Docker 容器网络,更好地满足了用户网络模型多样化的需求。

CNM 只是定义了网络标准,对于底层的具体实现并不太关心,这样便解耦了容器和网络,使得容器的网络模型更加灵活。

CNM 定义的网络标准包含三个重要元素。

  • 沙箱(Sandbox):沙箱代表了一系列网络堆栈的配置,其中包含路由信息、网络接口等网络资源的管理,沙箱的实现通常是 Linux 的 Net Namespace,但也可以通过其他技术来实现,比如 FreeBSD jail 等。
  • 接入点(Endpoint):接入点将沙箱连接到网络中,代表容器的网络接口,接入点的实现通常是 Linux 的 veth 设备对。
  • 网络(Network):网络是一组可以互相通信的接入点,它将多接入点组成一个子网,并且多个接入点之间可以相互通信。

为了更好地构建容器网络标准,Docker 团队把网络功能从 Docker 中剥离出来,成为独立的项目 libnetwork,它通过插件的形式为 Docker 提供网络功能。Libnetwork 是开源的,使用 Golang 编写,它完全遵循 CNM 网络规范,是 CNM 的官方实现。

2、Libnetwork的工作流程

Libnetwork 是 Docker 启动容器时,用来为 Docker 容器提供网络接入功能的插件,它可以让 Docker 容器顺利接入网络,实现主机和容器网络的互通。

第一步:Docker 通过调用 libnetwork.New 函数来创建 NetworkController 实例。NetworkController 是一个接口类型,提供了各种接口,代码如下:

type NetworkController interface {

   // 创建一个新的网络。 options 参数用于指定特性类型的网络选项。

   NewNetwork(networkType, name string, id string, options ...NetworkOption) (Network, error)

   // ... 此处省略部分接口

}

第二步:通过调用 NewNetwork 函数创建指定名称和类型的 Network,其中 Network 也是接口类型,代码如下:

type Network interface {

   // 为该网络创建一个具有唯一指定名称的接入点(Endpoint)

   CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error)

   // 删除网络

   Delete() error

// ... 此处省略部分接口

}

第三步:通过调用 CreateEndpoint 来创建接入点(Endpoint)。在 CreateEndpoint 函数中为容器分配了 IP 和网卡接口。其中 Endpoint 也是接口类型,代码如下:

// Endpoint 表示网络和沙箱之间的逻辑连接。

type Endpoint interface {

   // 将沙箱连接到接入点,并将为接入点分配的网络资源填充到沙箱中。

   // the network resources allocated for the endpoint.

   Join(sandbox Sandbox, options ...EndpointOption) error

   // 删除接入点

   Delete(force bool) error

   // ... 此次省略部分接口

}

第四步:调用 NewSandbox 来创建容器沙箱,主要是初始化 Namespace 相关的资源。

第五步:调用 Endpoint 的 Join 函数将沙箱和网络接入点关联起来,此时容器就加入了 Docker 网络并具备了网络访问能力。

3、Libnetwork常见网络模式

1、null空网络模式

有时候,我们需要处理一些保密数据,出于安全考虑,我们需要一个隔离的网络环境执行一些纯计算任务。这时候 null 网络模式就派上用场了,这时候我们的容器就像一个没有联网的电脑,处于一个相对较安全的环境,确保我们的数据不被他人从网络窃取。

使用 Docker 创建 null 空网络模式的容器时,容器拥有自己独立的 Net Namespace,但是此时的容器并没有任何网络配置。在这种模式下,Docker 除了为容器创建了 Net Namespace 外,没有创建任何网卡接口、IP 地址、路由等网络配置。我们可以一起来验证下。

我们使用 docker run 命令启动时,添加 --net=none 参数启动一个空网络模式的容器,命令如下:

# docker run --net=none -it busybox

容器启动后,我们使用ifconfig命令来查看一下容器内的网络配置信息

/ # ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) / #

可以看到容器内除了 Net Namespace 自带的 lo 网卡并没有创建任何虚拟网卡,然后我们再使用 route -n 命令查看一下容器内的路由信息:

/ # route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
/ #

可以看到容器内也并没有配置任何路由信息。

2、bridge桥接模式

Docker 的 bridge 网络是启动容器时默认的网络模式,使用 bridge 网络可以实现容器与容器的互通,可以从一个容器直接通过容器 IP 访问到另外一个容器。同时使用 bridge 网络可以实现主机与容器的互通,我们在容器内启动的业务,可以从主机直接请求。

我们需要先了解一下 Linux 的 veth 和 bridge 相关的技术,因为 Docker 的 bridge 模式正是由这两种技术实现的。

  • Linux veth

    veth 是 Linux 中的虚拟设备接口,veth 都是成对出现的,它在容器中,通常充当一个桥梁。veth 可以用来连接虚拟网络设备,例如 veth 可以用来连通两个 Net Namespace,从而使得两个 Net Namespace 之间可以互相访问。

  • Linux bridge

    Linux bridge 是一个虚拟设备,是用来连接网络的设备,相当于物理网络环境中的交换机。Linux bridge 可以用来转发两个 Net Namespace 内的流量。

我们可以看到,bridge 就像一台交换机,而 veth 就像一根网线,通过交换机和网线可以把两个不同 Net Namespace 的容器连通,使得它们可以互相通信。

Docker 的 bridge 模式也是这种原理。Docker 启动时,libnetwork 会在主机上创建 docker0 网桥,docker0 网桥就相当于图 中的交换机,而 Docker 创建出的 brige 模式的容器则都会连接 docker0 上,从而实现网络互通。

3、host主机网络模式

容器内的网络并不是希望永远跟主机是隔离的,有些基础业务需要创建或更新主机的网络配置,我们的程序必须以主机网络模式运行才能够修改主机网络,这时候就需要用到 Docker 的 host 主机网络模式。

使用 host 主机网络模式时:

  • libnetwork 不会为容器创建新的网络配置和 Net Namespace。
  • Docker 容器中的进程直接共享主机的网络配置,可以直接使用主机的网络信息,此时,在容器内监听的端口,也将直接占用到主机的端口。
  • 除了网络共享主机的网络外,其他的包括进程、文件系统、主机名等都是与主机隔离的。

host 主机网络模式通常适用于想要使用主机网络,但又不想把运行环境直接安装到主机上的场景中。例如我想在主机上运行一个 busybox 服务,但又不想直接把 busybox 安装到主机上污染主机环境,此时我可以使用以下命令启动一个主机网络模式的 busybox 镜像:

# docker run -it --net=host busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 00:0c:29:30:6d:8c brd ff:ff:ff:ff:ff:ff
inet 192.168.209.148/24 brd 192.168.209.255 scope global dynamic noprefixroute ens32
valid_lft 1478sec preferred_lft 1478sec
inet6 fe80::8081:c385:2b72:fe59/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue
link/ether 02:42:11:6b:1c:9b 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
/ #

可以看到容器内的网络环境与主机完全一致。

4、container网络模式

container 网络模式允许一个容器共享另一个容器的网络命名空间。当两个容器需要共享网络,但其他资源仍然需要隔离时就可以使用 container 网络模式,例如我们开发了一个 http 服务,但又想使用 nginx 的一些特性,让 nginx 代理外部的请求然后转发给自己的业务,这时我们使用 container 网络模式将自己开发的服务和 nginx 服务部署到同一个网络命名空间中。

下面我举例说明。首先我们使用以下命令启动一个 busybox1 容器:

# docker run -d --name=busybox1 busybox sleep 3600

然后使用docker exec命令进入到busybox1容器查看网络配置:

# docker exec -it busybox1 sh
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:13 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1182 (1.1 KiB) TX bytes:0 (0.0 B) lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) / #

可以看到 busybox1 的 IP 地址为 172.17.0.2。

然后我们新打开一个命令行窗口,再启动一个 busybox2 容器,通过 container 网络模式连接到 busybox1 的网络,命令如下:

# docker run -it --net=container:busybox1 --name=busybox2 busybox sh
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:14 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1252 (1.2 KiB) TX bytes:0 (0.0 B) lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) / #

可以看到 busybox2 容器的网络 IP 也为 172.17.0.2,与 busybox1 的网络一致。

Libnetwork底层原理以及Docker网络实现的更多相关文章

  1. Docker 网络背后的原理探索

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. 知其然而不知其 ...

  2. Docker底层原理介绍

    1.docker介绍 1.1什么是docker Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻 ...

  3. 2、docker安装:内核要求、docker三要素、安装、helloworld、底层原理

    1.前提说明 1.CentOS Docker 安装 Docker支持以下的CentOS版本: CentOS 7 (64-bit) CentOS 6.5 (64-bit) 或更高的版本 2.前提条件:内 ...

  4. Docker 网络原理

    引言 学习docker网络,可以带着下面两个问题来探讨 容器之间可以相互访问的原理 容器暴露端口后,通过宿主机访问到容器内应用,并且对于访问端而言不用感知容器存在的原理 Docker 本身的技术依赖L ...

  5. 『现学现忘』Docker基础 — 16、Docker中的基本概念和底层原理

    目录 1.Docker的底层原理 2.Docker中常用的基本概念 3.run命令的运行流程 4.为什么Docker比VM快 Docker架构图: 我们依照Docker架构图进行Docker基础概念的 ...

  6. 【Socket】linux黑客之网络嗅探底层原理

      1.mystery引入 1)网络嗅探属于网络攻防类的安全软件,其基于原始套接字技术开发的 2)原始套接字是一种套接字底层技术,它工作在网络层 3)谈到网络安全,刚好本学期学过这门课程,这里myst ...

  7. Docker进阶:容器卷、DockerFile、Docker网络原理

    1.Docker镜像 1.1镜像是什么 镜像是一种轻量级.可执行的独立软件包,用来打包软件运行环境和机遇运行环境开发的软件. 包含一个软件的所有内容.蒋所有的应用和环境,直接打包为docker镜像,直 ...

  8. 理解Docker(5):Docker 网络

    本系列文章将介绍 Docker的相关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...

  9. 深入解读docker网络与kubernetes网络

    前言:你是否学习使用k8s很久很久了可是对于网络这块仍旧似懂非懂呢? 您是否对网上一堆帖子有如下的抱怨: 打开多个博客,然后发现有区别么? 明显是直译过来的,越看越迷糊 “因为xxx,所以yyy”,. ...

  10. 理解Docker :Docker 网络

    本系列文章将介绍 Docker的相关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...

随机推荐

  1. java如何实现对List集合进行分页

    对List集合进行分页: private <T> Page<T> listToPage(List<T> dataList, Integer pageSize, In ...

  2. Ribbon-Loadbalancer自定义负载均衡策略:本地优先+偏向服务器优先

    Ribbon 核心顶层抽象 package com.netflix.loadbalancer; public interface IRule { Server choose(Object var1); ...

  3. OkHTTP发送POST请求传送JSON数据

    导入依赖 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> ...

  4. Docker使用手册--给你通用常用命令

    卸载JDK rpm -qa | grep -i java rpm -qa | grep -i java | xargs -n1 rpm -e --nodeps 安装JDK tar -zxvf jdk- ...

  5. 通过百度地图 API V2.0 版本,进行地图坐标系转换

    注意 先阅读参考链接 瞭月 的文章,再阅读本文. 其中,请求参数中 model 的含义: amap/tencent - 即:GCJ02 火星坐标系,由中国国家测绘局制订的地理信息系统的坐标系统. 由 ...

  6. Object类--toString方法--java进阶day05

    1.Object类.以及通用的类 2.toString方法 默认的toString方法,返回的是地址值(全类名再加上通过地址值算出来的十六进制哈希值) . 为什么打印语句会自动调用toString方法 ...

  7. Codeforces Round 954 (Div. 3)

    A. X Axis 1.既然要求每个点到a到距离之和最小,不妨让点a为3个点中的中间点,也就是先对三个数从小到大排序,然后输出首尾数减中间值的绝对值之和即可 #include <bits/std ...

  8. Jmeter参数化总结

    参数化步骤: 1.连接数据库 2.获取account表手机号数据 3.获取手机号个数 4.增加For Each控制器 5.将请求添加至循环控制器里面 脚本:循环登录.jmx 页面如下: 下面主要说明F ...

  9. Debug调试(使用IDEA的断点调试功能,查看程序的运行过程)

    一. 1. 在有效代码行,点击行号右边的空白区域,设置断点,程序执行到断点将停止,我们可以手动来运行程序 2. 点击Debug运行模式 3. 程序停止在断点上不再执行,而IDEA最下方打开了Debug ...

  10. 使用CAMEL创建第一个Agent Society

    CAMEL介绍 CAMEL 是一个开源社区,致力于探索代理的扩展规律.相信,在大规模研究这些代理可以提供对其行为.能力和潜在风险的宝贵见解.为了促进这一领域的研究,实现了并支持各种类型的代理.任务.提 ...