容器网络笔记(一)

引言

------------------------------------------------------------------------------

整体学习内容

一、容器及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.虚拟机

      容器没有为每个应用穿建独立的虚拟操作系统,轻量化,节省主机资源。

      容器按需使用资源,避免底层资源的浪费。 

容器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

创建Docker test1
创建Docker test2

(2) 若长时间未用,首先需要先启动Docker

    sudo docker start test1

进入docker 容器

    sudo  docker attach test1

test1 可以ping 通test2,通过bridge二层转发
查看主机的ip tables nat 表
查看当前Docker 下的网络 docker network ls

查看当前Docker下的网络,“bridge”是默认的“Docker0”下的网络

创建Docker 网络“isolate”

查看主机的网络地址: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”的容器            

网络模式是none的容器

        登录容器,查看网卡,可以看到容器下没有任何网卡,只有loopback,路由表也为空:

(2)创建一个网络模式为“host”的容器  :

网络模式是host对的容器

       查看网络类型为host的test2容器的网络接口,以及路由,他们与主机网络的配置一致:

1.11  Docker Network (MACVLAN)

            MACVLAN是linux  sub-interface 的一种实现。linux  sub-interface  是linux丰富的虚拟网络功能的一种,是可以在一个netdev设备上挂载多个虚拟的子网卡,子网卡向外界访问需要通过netdev设备来传输。

sub1 与sub2是虚拟子网卡

        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),无需多说

pi

用途:域名解析,负载分担(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

可以看到容器无法解析“test1”

    查看容器空间local host

可以看到有容器IP地址到uuid的对应关系,但是没有到“名字的对应关系”

    查看容器空间的hostname

docker空间中,hostname是容器的uuid

    查看容器空间name解析配置

nameserver 是主机

     查看主机空间的名字解析

解析server与容器一样

#得到Docker把主机空间的resolv.conf 拷贝到了容器里。

(2)指定Docker的DNS

创建Docker test2 并指定它的hostname为test2

cat  /etc/hosts 中 docker 对应IP地址的已经不是uuid,而是hostname了:

(3)创建容器test4

查看容器的DNS server配置:

dns server 是8.8.8.8

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

你可能感兴趣的:(容器网络笔记(一))