引言
------------------------------------------------------------------------------
整体学习内容
一、容器及Docker网络实现
二、Kubernetes 网络实现
三、Flannel
四、Calico
五、Kuryr-Kubernetes
------------------------------------------------------------------------------
一、容器及Docker网络实现
1.1 容器基础
容器的优势(vs. 虚拟机)
(1) 容器也是一种虚拟化技术
(2)应用程序如何在操作系统运行
应用程序是一段运行的代码,需要依赖第三方的库文件,库文件一般放在操作系统的bins/ 或 lib/目录下,bin 文件会连接应用程序以及底层的操作系统,操作系统在连接底层硬件,这样应用程序才可以在硬件上运行起来。
(3) 应用程序如何在虚拟机运行
虚拟机通过Hpervisor ,为应用程序创建了一个个独立的操作系统。
(4) 因用程序如何在容器运行
容器没有为每个应用程序创建操作系统,为应用程序提供一个应用“引擎”--Container Engine。
在容器引擎中,创建独立的第三方库,不同的bins/lib 文件;库文件与容器引擎交互,而不是与底层硬件交互。
(5) 容器v.s.虚拟机
容器没有为每个应用穿建独立的虚拟操作系统,轻量化,节省主机资源。
容器按需使用资源,避免底层资源的浪费。
(6) 容器的优势
i 可移植性强
ii 可以通过容器组织大型应用
容器的技术
(1) 隔离技术
容器是应用程序的容器,为应用程序的进程提供了隔离的环境,对于这些进程,容器就相当于是虚拟机。
*namespace(命名空间)
namespace是linux本身就支撑的功能,有很多种,每种都支持了不同的资源。
不同namespace之间不能互访
namespace有四种:
PID namespace, 第一个启动的进程为1
User namespace, 隔离User ID
Mount namespace, 文件系统隔离
Network namespace, 网络隔离,可以隔离网卡,不能通过主机的协议栈直接转发,要转发到主机后,才可以。独立的路由表,独立的路由策略等。
*cgroups(2006年由谷歌工程师提出的概念)
cgroups =linux contriol groups
可以对CUP,内存,网络IO等资源进行隔离,实现精细化的管理,可以限制使用的容量,可以实现应用程序建资源的分配合管理、隔离
总之,容器是针对进程提供的隔离。
(2)网络连接
容器之间,通过网络连接起来,进而构成一个大型的应用。
1.2 Docker简介
Docker 是目前最流行的一个容器引擎。是基于Linux LXC来实现的, 而LXC又是基于cgroups 和 namespace的隔离特性来实现的具体功能。 Docker就是创建cgroups 和namespace来实现。但是是否可以运行应用进程呢?还是不可以,因为还要需要库文件等,需要bin和lib文件,Docker用Image 来解决这个问题。
(1)Docker的运行:
(2) 容器编排:
早期的Docker是为了在一个主机上运行多个进程而开发的,但对于大型应用,以及微服务框架来说,是需要构建大量的分布在不同主机上的容器,需要同时管理这些容器的网络、文件系统、资源、生命周期等等,单纯的Docker是不能满足这些更高级别的要求的。
因此,在Docker之上又出现了各种编排的软件系统。常见的有:
Docker Swarm
Kubernetes (google 开源)
Apache Mesos
1.3 Libnetwork
是CNM(container network model)的一个实现。是Docker提出的容器网络标准。
* 通过插件形式为Docker提供网络功能
*创建容器和网络的过程是解耦的
*使得Docker 可以支持多种类型的网络
CNM 有上面所列三种组件:
Endpoint: 端点,对应容器的网卡。由Veth pair (Veth 对)实现,Veth是Linux中的Netdev设备,Netdev是Linux中接收和发送网络数据包设备的一个抽象。可以对应一个硬件设备,如物理网卡;也可以是一个软件设备。
Veth 成对出现,从一个Veth 送出,可以从与其配对的另一个Veth收到。可以理解为一个主机内部的管道。在Docker中,一对Veth 是连接容器与主机。一对Veth也可以连接两个容器。
Network ,用来连接一组Endpoint。
Network由Linuxbridge来实现的,也是Netdev设备,可以实现二次、三层转发。一对Veth,一端接容器,另一端接主机,接主机的就是接在主机的linuxbridage上,可以用br-ctl来进行管理。Docker会创建一个默认的为“0” linuxbridge, 是Docker提供的一个默认的网络,如果不特殊指定,Docker中的Veth对都挂在默认“0”的linuxbridge网络上。
Sandbox, 为容器提供网络协议栈,包括容器的网卡存放空间,容器路由表,容器DNS等。
通过“Network namespace”来实现的。提供基于容器的隔离网络环境。用户可以在linux下创建任意多个Network namespace, namespace之间相互隔离,namespace之间的通信是不能通过内核之间传输的,也就是说直接的内存拷贝是不行的,需要经过一个转发。每一个容器都有自己的Network namespace, 可以通过一对Veth将两个Network namespace连接起来。
1.4 Docker 环境安装
1.5 创建第一个容器
在主机中多了一个连接容器的“veth”接口 @if4 说明连接容器“busybox”的if 4
查看sandbox(由linux的network namespace 来实现的),ip netns
删除容器:先停后删
docker stop test
docker rm test
1.6 容器网络标准
CNM: Container Network Model 容器网路模型
CNI : Container Network Interface 是CNCF的项目, 更简单,更灵活
代表有:Kubernetes, rkt, Mesos
1.7 Docker Network Bridge模式
(1) Bridge
同一个Bridge上的两个容器,是可以通过二层转。发来实现。
(2) 访问外网
Docker需要访问外部网络,需要通过主机空间的iptables NAT表 来实现。
(3)举例: Container1访问谷歌DNS8.8.8.8
Container1---->Docker0(位于主机网络空间)---->查找主机网络空间的iptables 规则---->在主机网络空间作NAT操作。
(4) Docker 默认创建Docker0的 Linux Network Bridge。
用户可以任意创建Docker network。
一个Docker bridage network 就是一个Linuxbridge
"docker network create --driver bridge isolated_nw"
(5) 每个linuxbridge是一个独立的二层广播域
但是Docker 会对不同的Docker Bridge network 做隔离,通过iptables Filter table 来实现。
一个主机上可以有任意多个Docker bridge network.
一个Docker容器可以同时存在于多个Docker bridge network上, 每个容器在每个Network上都有一个Endpoint。
(6) Publish Port
同一个Docker BridgeNetwork下的Docker 可以通过二层转发实现访问;
不同Docker Bridge Network 下的Docker 是隔离的,不能互访。
Docker 访问外网。
外网访问Docker,不能用NAT, 使用Publish Port来实现;将容器的某一个端口映射到主机空间的某一个端口(端口映射)
i. Publish Port 随机分配主机端口,(大于30000)
docker run -it -d -p 80 nginx
ii. Publish Port 指定主机端口
docker run -it -d -p 8080:80 nginx
iii. 映射UDP端口,通过后缀 publish udp
docker run -it -d -p 80/udp nginx
1.8 Docker Network Bridge实验
(1)创建2个实验容器:test1 、test2
(2) 若长时间未用,首先需要先启动Docker
sudo docker start test1
进入docker 容器
sudo docker attach test1
查看当前Docker下的网络,“bridge”是默认的“Docker0”下的网络
查看主机的网络地址:ip a
"Docker0"是默认的Docker0 网络,网络地址是172.17.0.0/16
"br-b8aa02a200b8"是刚才创建的“isolated-net”网络,网络地址是172.18.0.0/16
“veth235da85@if5”和“veth18dde49@if7”分别是test1和test2的网络
使用“brctl show” 来看主机里的网桥:
可见新增的网桥“isolated-net”网络里没有接口,所以给它新增一个容器:
docker run -it -d --network=isolated_nw --name=test3 busybox:
"docker ps" 查看主机中的容器,发现新增的test3:
再看主机的网络空间:ip a ,新增了网络接口“vetha06020f@if9”,它连接新增的Docker test3与主机空间:
“brctl show” 验证:
进入容器test3 查看网络空间:
在容器test3上ping test2的接口是不通的,隔离的:
再在主机上看iptables," iptables -t -vnL", 看到主机会为2个Docker网络创建2个“stage”,到另个Docker的数据报被丢弃了:Docker之间的网络隔离是依靠主机路由表中的filter来实现的。
"test3"与"test2"如何联通呢?把test3连接到“Docker0”默认的网络“bridge”:
docker network connect bridge test3,后再看主机网络空间,为test3新建了主机网卡12:"veth2624851@if11":
这个新增的网卡,挂载在哪里呢,挂载在Docker0网络中:
可以看到test3中也新增了一个网络接口“eth1@if12”:
(3) poblishpod的功能:把容器端口映射到主机端口
创建一个nginx镜像的容器,把主机端口32768映射到了容器的80端口(TCP):
验证,主机通过32768端口访问到了容器开放的nginx服务:
用主机的浏览器验证,说明容器的80端口已发布出来:
以上功能,主机是如何来实现的呢?是通过iptables nat来实现的,把容器的80端口和主机的8080端口关联起来,发布出去:
1.9 Docker Network (None & Host)
通过Docker Network list ,我们可以看到,除了默认创建了Docker0 外,我们还创建了另外两个网络:None 和Host
(1) None 模式
Docker创建了一个与外界网络隔离的容器 ,Docker不会创建CNM对应的Endpoint,也就是这类容器没有网卡(Veth)和 Bridge Network;只会创建Sandbox。
这类容器没有网络连接的需求,所以并不会创建endpoint对应的网卡,也就是没有veth,以及network对应的linux bridge,;因为容器在网络上是隔离的,所以不需要以上组件。
网络是none的容器创建后,Docker不允许将这类容器连接到其他网络。虽然没有网络的连接,但是还可以通过mont,namespace来读取主机的文件,
用途:
i. 完全隔离的容器,只执行主机范围内的计算。
ii.被其他network plugin (calico,weave) 用来禁用Docker自身的网络,进而提供network plugin的network stack ,可以通过这些专用的network stack 协议栈类通信,这些网络协议栈与Docker的网络协议栈是冲突的,所以通过none模式来禁用Docker自身的网络,再加载calico,weave自身的网络。
(2) Host 模式
比none模式更加精简,直接将容器接入主机网络,Docker完全放弃了自己的网络,Docker 不会创建任何额外资源(sandbox对应的network-namespace,endpoint和network)
直接连接主机,Docker不会管理它的网络,也就host放弃了容器的网络隔离性
应用:迁移原来运行在主机环境里的进程与应用,用于直接将主机内的应用迁移进容器。
1.10 Docker Network (None & Host)实验
(1)创建一个网络模式为“none”的容器
登录容器,查看网卡,可以看到容器下没有任何网卡,只有loopback,路由表也为空:
(2)创建一个网络模式为“host”的容器 :
查看网络类型为host的test2容器的网络接口,以及路由,他们与主机网络的配置一致:
1.11 Docker Network (MACVLAN)
MACVLAN是linux sub-interface 的一种实现。linux sub-interface 是linux丰富的虚拟网络功能的一种,是可以在一个netdev设备上挂载多个虚拟的子网卡,子网卡向外界访问需要通过netdev设备来传输。
MACVLAN 可以在一个网卡上创建多个macvlan类型的子接口,这些网络子接口有不同的二层地址(mac地址)和不同的三层地址(ip地址),所以可在原来物理网卡上虚拟出多个独立的逻辑子网卡
每个MACVLAN子接口都有独立的IP和MAC地址
会增加IP地址和MAC地址,增加物理网络负担
要支持MACVLAN功能,需要物理网络设备(网卡)打开混杂模式promiscuous mode
linux kernel v3.9-3.19 v4.0+ 以上支持
(1) 连接物理网络的方式
MACVLAN (见上)
Host模式 (将容器直接接入到主机的网络空间,不能从IP,协议栈、端口范围对容器做一个区分和隔离,也就是HOST模式的网络是不隔离的,但是MACVLAN可以实现以上)
Linuxbridge (通常连接虚拟网络再通过三层转发与外网通信;也可以直接挂载物理网卡,从而实现将连接linuxbridge 虚拟网络的流量直接转发到物理网卡,问题:linuxbridge是一个bridge的软件实现,需要实现大量协议,是一个重量级的解决方案,支持flood-learn, STP等 ,网络性能开销大,增加复杂度;用MACVLAN可以替代linuxbridge 来实现需求,获得更好的性能)
(2) MACVLAN的4种工作模式
Passthru模式:在一个主机上配置一个MACVLAN的子接口,
(3) Docker MACVLAN的实现
Docker 的网络是通过libnetwork来实现的,又是基于CNM模型来实现的,Docker 会为MACVLAN创建sandBox, Endpoint, 和Network.
sandBox对应 network namespace
Endpoint对应MACVLAN,每个容器的Endpoint对应已一个MACVLAN子接口
Network 对应主机的网卡,就是MACVLAN所连接的网卡
Docker 从1.12版本开始支持
“-o” 指挂载在哪个物理网卡上。
(4) 同主机多个MACVLAN类型网络
通过VLAN子接口来实现同一个主机上同时去创建多个MACVLAN的网络
VLAN子接口是一种linux sub-interface, 通过挂载的网卡送出的以太帧带相应的VLAN ID, 物理网卡连接的交换机端口必须配置成TRUNK模式,使得同一块物理网卡可以连接到不同VLAN网络
1.12 Docker Network (MACVLAN)
docker network create -d macvlan --subnet=x.x.x.x/x --ip-range=x.x.x.x/x --gateway=x.x.x.x -o parent=ensx macvlanx
查看Docker 网络:
创建MACVLAN后,linux的网络空间没有发生变化,
1.13 Docker DNS
DNS 域名系统(Domain Name System),无需多说
用途:域名解析,负载分担(GLSB),CDN
Linux系统的DNS实现:
i.指定DNS Server /etc/resolv.conf
ii.在访问DNS Server 之前,会先访问本地静态文件的记录 /etc/hosts
iii.当前主机的域名 /etc/hostname
(1) 默认Docker网络Docker0 的DNS实现
Docker把主机etc/resolv.conf文件的文件拷贝给容器,容器直接使用主机的DNS配置,Docker没有提供DNS服务,而是直接使用主机的,Docker进程会监听主机的etc/resolv.conf文件,一旦发生变化,Docker会随之更新。
--hostname,指定容器的DNS主机名,修改/etc/hosts, 修改/etc/hostname
--link,修改容器内的DNS记录内容,可以修改多条记录内容
--dns , --dns-search , --dns-opt
指定Docker内的DNS配置,而不再使用主机的DNS配置
(2)Docker 用户自定义网络的DNS实现
i. 容器的/etc/resolv.conf 由Docker生成,指向127.0.0.11
ii. Docker拦截目的IP地址是127.0.0.11,端口是53的UDP和TCP请求,转发到docker进程上,Docker知道所有容器的名字与IP地址的对应关系,可以完成解析
iii. 如果Docker不能解析域名, Docker进程将会根据主机配置的DNS Server 完成域名解析请求
iv. --name 指定容器名,也是对应于容器IP的域名
--network-alias 为容器指定其他域名,可以增加多个容器名
--link 增加静态DNS记录,修改etc/hosts 文件
--dns --dns-search --dns-opt 指定fallback DNS server, 取代主机配置的DNS server
1.14 Docker DNS实验
(1)默认Docker 下的DNS
创建容器test1
#docker run -itd --name test1 busybox
登录容器test1
#docker attach test1
在容器中测试DNS
(docker)#ping test1
查看容器空间local host
查看容器空间的hostname
查看容器空间name解析配置
查看主机空间的名字解析
#得到Docker把主机空间的resolv.conf 拷贝到了容器里。
(2)指定Docker的DNS
创建Docker test2 并指定它的hostname为test2
cat /etc/hosts 中 docker 对应IP地址的已经不是uuid,而是hostname了:
(3)创建容器test4
查看容器的DNS server配置:
1.15Docker Network 命令总结
(1)容器网络
#创建一个用户自定义的Docker 网络
docker network create
#查看Docker网络
docker network ls
#删除Docker网络
docker network rm
#查看Docker网络详细信息
docker network inspect
# 将一个现成的容器与加入到某个Docker network
docker network connect
为容器添加一块网络网卡
#将一个现成的容器从某个docker network移除
docker network disconnet
(2)容器调试
#查看容器详细配置信息(IP,镜像等)
docker inspect
#查看log
docker logs
#连接到容器主进程上
docker attach
#通过容器执行命令
dokcer exec -it