libnetwork介绍

之前文章中介绍Docker的时候,我们看到Docker中的网络相关的操作是由libnetwork来实现的。这里我们来介绍下这个libnetwork的一些概念以及使用方法。目前libnetwork的开发速度非常快,读者如果有兴趣深入的话可以以本节的内容为基础然后自行的去研究最新的实现。

目前关于libnetwork的文档基本上只有其GitHub上的docs目录下的一些文件以及README.md文件。下面的内容基本上很多都可以这些文档中找到。

1. libnetwork开发环境的搭建
首先先来看下如何使用libnetwork这个库。直接从Docker中学习用法当然是可以的,不过那个会需要对Docker有一定的熟悉,所以这里小秦先列了一个测试、开发环境的搭建方法,便于大家以后研究。

首先下载libnetwork的代码,以后要开发的话直接在这个代码上进行开发即可:

[root@dev tmp]# git clone https://github.com/docker/libnetwork.git
正克隆到 'libnetwork'...
remote: Counting objects: 4281, done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 4281 (delta 1), reused 0 (delta 0), pack-reused 4272
接收对象中: 100% (4281/4281), 4.73 MiB | 95.00 KiB/s, done.
处理 delta 中: 100% (2001/2001), done.

接着我们建立一个项目来存放我们的调试用代码,首先建立如下目录结构:

[root@dev bingo]# pwd
/tmp/bingo
[root@dev bingo]# ls
bin  lib  Makefile  src

Makefile内容如下:

[root@dev bingo]# cat Makefile 
.PHONE: build clean

GOPATH := ${PWD}/lib:${GOPATH}
export GOPATH

build:
    go build -v -o ./bin/bingo ./src/bingo

clean:
    rm -f ./bin/bingo

src目录下存放我们的调试用代码,目录结构及调试文件内容如下:

[root@dev src]# tree
.
└── bingo
    └── bingo.go

1 directory, 1 file
[root@dev src]# cat bingo/bingo.go 
package main

import (
    "fmt"

    "libnetwork"
)

func main() {
    controller, err := libnetwork.New()
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(controller)
}

lib目录存放我们的依赖包,首先将我们上面git下来的libnetwork放到lib下的src目录下,然后从Docker的代码处拷贝其它的依赖到对应目录,并将Docker中的libnetwork替换为到我们git下来的libnetwork目录的软链:

[root@dev src]# pwd
/tmp/bingo/lib/src
[root@dev src]# ls
github.com  libnetwork
[root@dev github.com]# ls
armon       coreos  fluent    godbus  gorilla   hashicorp  microsoft  natefinch  samuel    syndtr  tinylib
BurntSushi  docker  go-check  golang  Graylog2  kr         mistifyio  philhofer  Sirupsen  tchap   vishvananda
[root@dev github.com]# cd docker/
[root@dev docker]# ls -l
总用量 8
drwxr-xr-x  4 root root   34 8月  24 23:13 distribution
drwxr-xr-x  3 root root   16 8月  24 23:14 docker
drwxr-xr-x 16 root root 4096 8月  24 23:13 libcontainer
drwxr-xr-x  3 root root   81 8月  24 23:13 libkv
lrwxrwxrwx  1 root root   29 8月  24 23:13 libnetwork -> /tmp/bingo/lib/src/libnetwork
drwxr-xr-x  3 root root 4096 8月  24 23:13 libtrust

这些都设置好后执行make编译我们的执行文件bingo:

[root@dev bingo]# pwd
/tmp/bingo
[root@dev bingo]# make
go build -v -o ./bin/bingo ./src/bingo
github.com/Sirupsen/logrus
github.com/docker/docker/pkg/ioutils
github.com/docker/docker/pkg/listenbuffer
github.com/docker/libcontainer/user
github.com/docker/docker/pkg/stringid
github.com/docker/libkv/store
github.com/BurntSushi/toml
github.com/docker/libnetwork/netlabel
github.com/hashicorp/consul/api
github.com/coreos/go-etcd/etcd
github.com/docker/docker/pkg/sockets
github.com/docker/docker/pkg/tlsconfig
github.com/docker/docker/pkg/plugins
github.com/docker/libkv/store/etcd
github.com/docker/libnetwork/config
github.com/samuel/go-zookeeper/zk
github.com/docker/libkv/store/consul
github.com/docker/libnetwork/types
github.com/docker/docker/pkg/parsers/kernel
github.com/vishvananda/netlink/nl
github.com/docker/libnetwork/driverapi
github.com/godbus/dbus
github.com/docker/libnetwork/options
github.com/docker/docker/pkg/proxy
github.com/vishvananda/netlink
github.com/docker/docker/pkg/reexec
github.com/docker/libnetwork/portallocator
github.com/docker/libnetwork/drivers/host
github.com/docker/libnetwork/drivers/null
github.com/docker/libkv/store/zookeeper
github.com/vishvananda/netns
github.com/docker/libkv
github.com/armon/go-metrics
github.com/docker/libnetwork/datastore
github.com/hashicorp/go-msgpack/codec
github.com/docker/libnetwork/netutils
github.com/docker/libnetwork/ipallocator
github.com/docker/libnetwork/bitseq
github.com/docker/libnetwork/sandbox
github.com/docker/libnetwork/idm
github.com/docker/libnetwork/drivers/remote/api
github.com/docker/libnetwork/drivers/remote
github.com/docker/libnetwork/iptables
github.com/docker/libnetwork/etchosts
github.com/docker/libnetwork/hostdiscovery
github.com/docker/libnetwork/resolvconf/dns
github.com/docker/libnetwork/resolvconf
github.com/docker/libnetwork/portmapper
github.com/docker/libnetwork/drivers/bridge
github.com/hashicorp/memberlist
github.com/hashicorp/serf/serf
github.com/docker/libnetwork/drivers/overlay
libnetwork
_/tmp/bingo/src/bingo

此时我们的调试用代码就能用上git下载下来的libnetwork包了:

[root@dev bingo]# bin/bingo 
WARN[0000] Running modprobe bridge nf_nat br_netfilter failed with message: modprobe: WARNING: Module br_netfilter not found.
, error: exit status 1 
INFO[0000] Firewalld running: false                     
&{map[] map[null:0xc20810bc40 overlay:0xc20810bc60 bridge:0xc20810bbc0 host:0xc20810bc00] map[] <nil> <nil> {0 0}}

2. libnetwork设计思想

libnetwork实现了一个叫做Container Network Model (CNM)的东西,也就是说起希望成为容器的标准网络模型、框架。其包含了下面几个概念:

* Sandbox。对于Sandbox大家就认为是一个namespace即可。联系我们前面Kubernetes中说的Pod,Sandbox其实就是传统意义上的虚拟机的意思。
* Endpoint。Neutron中和Endpoint相对的概念我想应该是VNIC,也就是虚拟机的虚拟网卡(也可以看成是VIF)。当Sandbox要和外界通信的时候就是通过Endpoint连接到外界的,最简单的情况就是连接到一个Bridge上。
* Network。libnetwork中的Network大家就认为是Neutron中的network即可,更加贴切点的话可以认为是Neutron中的一个拥有一个subnet的network。

上面这三个概念就是libnetwork的CNM的核心概念,熟悉了Neutron后并不会对这几个概念在理解上有多大问题。下面我们看下libnetwork为了对外提供这几个概念而暴露的编程结构体:

* NetworkController。用于获取一个控制器,可以认为通过这个控制器可以对接下来的所有网络操作进行操作。Neutron中并没有这么一个概念,因为Neutron中的网络是由agent通过轮询或者消息的方式来间接操作的,而不是由用户使用docker命令直接在本机进行操作。
* Driver。这里的Driver类似于Neutron中的core_plugin或者是ml2下的各种driver,表示的是底层网络的实现方法。比如有bridge的driver,也有基于vxlan的overlay的driver等等。这个概念和Neutron中的driver概念基本上是一样的。
* Network。这里的Network结构体就是对应的上面CNM中的Network,表示建立了一个网络。通过这个结构体可以对建立的网络进行操作。
* Endpoint。这里的Endpoint结构体就是对应上面CNM中的Endpoint,表示建立了一个VNIC或者是VIF。通过这个结构体可以对Endpoint进行操作。
* Sandbox。这里的Sandbox结构体就是对应上面CNM中的Sandbox,表示建立了一个独立的名字空间。可以类比Nova的虚拟机或者是Kubernetes的Pod,亦或是独立的Docker容器。

接着我们看下一般使用libnetwork的方法,具体的步骤一般是下面这样的:

1. 获取一个NetworkController对象用于进行下面的操作。获取对象的时候指定Driver。
2. 通过NetworkController对象的NewNetwork()建立一个网络。这里最简单的理解就是现在我们有了一个bridge了。
3. 通过网络的CreateEndpoint()在这个网络上建立Endpoint。这里最简单的理解就是每建立一个Endpoint,我们上面建立的bridge上就会多出一个VIF口等着虚拟机或者Sandbox连上来。假设这里使用的是veth,则veth的一头目前接在了bridge中,另一头还暴露在外面。
4. 调用上面建立的Endpoint的Join方法,提供容器信息,于是libnetwork的代码就会建立一个Sandbox对象(一般这里的Sandbox就是容器的namespace,所以不会重复建立),然后将第三步建立的veth的一头接入到这个Sandbox中,也就是将其放到Sandbox的namespace中。
5. 当Sandbox的生命周期结束时,调用Endpoint的Leave方法使其从这个Network中解绑。简单的说就是将veth从Sandbox的namespace中拿出来回到物理机上。
6. 如果一个Endpoint无用了,则可以调用Delete方法删除。
7. 如果一个Network无用了,则可以调用Delete方法删除。

关于libnetwork小秦就说这么多。通过这些大家应该能基本的清楚libnetwork的基本思想、用法以及开发环境的搭建。小秦在看过libnetwork之后,相比较容器小秦就更对Kubernetes的网络感兴趣些。目前的基于libnetwork的Docker基本还是一个单机环境,虽然其roadmap中也有多节点的支持,但小秦认为从一个类库出发提供一套多节点的网络环境并不是一个最好的方法。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*