4.容器虚拟化网络概述

部分内容来自地址:https://blog.51cto.com/gouyc/2312408

一、docker网络简介

网络作为docker容器化实现的6个名称空间的其中之一,是必不可少的,其在Linux内核2.6时已经被加载进内核支持了。网络名称空间主要用于实现网络设备和协议栈的隔离,例如:某个docker host有4块网卡,在创建容器的时候,将其中一块网卡分配给该名称空间,那么其他名称空间是看不到这块网卡的。且:一个设备只能属于一个名称空间。因为一个名称空间绑定一个物理网卡和外界通信,且一个物理网卡不能分配多个名称空间,这使得我们只能创建4个名称空间。如果要创建的名称空间多于我们的物理网卡数量,那该怎么办呢?

 1、 虚拟网络通信的三种方式

1.1、桥接网络

在kvm的虚拟网络中,我们使用的是虚拟网卡设备(用纯软件的方式来模拟一组设备来使用),而在docker中,也不例外。在Linux内核级,支持两种级别设备的模拟,分别是2层设备(工作在链路层能实现封装物理报文并在各网络设备中报文转发的组件);而这个功能,是可以在Linux上利用内核中对二层虚拟设备的支持创建虚拟网卡接口的。而且,这种虚拟网卡接口非常独特,每一个网络接口设备是成对出现的,可以模拟一根网线的两端,其中,一端可以插在主机上,另一端可以插在交换机上。这就相当于让一个主机连接到一个交换机上了。而Linux内核原生支持二层虚拟网桥设备(用软件来构建一个交换机)。例如;我有两个名称空间,都分别使用虚拟网络创建一对网络接口,一头插在名称空间上,另一头插在虚拟网桥设备上,并且两个名称空间配置在同一个网段上,这样就实现了容器间的通信,但是这种桥接方式,如果用在有N多个容器的网络中,由于所有容器全部是桥接在同一块虚拟网桥设备上,会产生广播风暴,在隔离上也是极为不易的,因此在规模容器的场景中,使用桥接这种方式无疑是自讨苦吃,否则都不应该直接桥接的。

1.2、nat网络

如果不桥接,又能与外部通信,用的是nat技术。NAT(network address transfer)网络地址转换,就是替换IP报文头部的地址信息,通过将内部网络IP地址替换为出口的IP地址提供不同网段的通信。比如:两个容器都配置了不同的私网地址,并且为容器配置了虚拟网桥(虚拟交换机),把容器1的网关指向虚拟网桥的IP地址,而后在docker host上打开核心转发功能,这时,当容器1与容器2通信时,报文先送给各自的虚拟网桥经由内核,内核判定目的IP不是自己,会查询路由表,而后将报文送给对应的网卡,物理网卡收到报文之后报文的原地址替换成自己的IP(这个操作称为snat),再将报文发送给容器2的物理网卡,物理网卡收到报文后,会将报文的原IP替换为自己的IP(这个操作称作dnat)发送给虚拟交换机,最后在发送给容器2。容器2收到报文之后,同样的也要经过相同的操作,将回复报文经过改写原ip地址的操作(snat和dnat)送达给容器1的物理网卡,物理网卡收到报文之后在将报文转发给虚拟网桥送给容器1。在这种网络中,如果要跨物理主机,让两个容器通信,必须经过两次nat(snat和dnat),造成了通信效率的低下。在多容器的场景中也不适合。

 1.3、Overlay Network

叠加网络,在这种网络中,不同主机的容器通信会借助于一个虚拟网桥,让当前主机的各个容器连接到这个虚拟网桥上来,随后,他们通信时,借助物理网络,来完成报文的隧道转发,从而可以实现容器可以直接看到不同主机的其他容器,进而互相通信。例如;容器1要和其他host上的容器2通信,容器1会把报文发送给虚拟网桥,虚拟网桥发现目的IP不在本地物理服务器上,于是这个报文会从物理网卡发送出去,在发出去之前不在做snat,而是在添加一层IP报头,原地址是容器1的物理网卡地址,目的地址是容器2所在主机的物理网卡地址。报文到达主机,主机拆完第一层数据报文,发现还有一层报头,并且IP地址是当前主机的容器地址,进而将报文发送给虚拟网桥,最后在发送给容器2。这种用一个IP来承载另外一个IP的方式叫做隧道。

2、docker的四种网络模型

  • bridge模式:Bridged container,docker默认的网络模型,容器网络接入到docker0网络上,是nat。
  • host模式:open container,让容器使用宿主机的网络名称空间,容器看到的网卡是物理机的网络设备,修改网络信息会直接修改宿主机的网络设备信息。
  • none模式:Closed container,只有loop接口,没有其他网卡,不使用网络通信。
  • container模式:joined container,让两个容器有一部分名称空间(User、Mount、Pid)隔离,其他名称空间(UTC、Network、IPC)共享,两个容器间就拥有同一个网络接口,网络协议栈。共享容器一个已经创建的容器的名称空间,两个容器的进程可以通过lo网卡设备通信。

二、操作

1、常用命令

[root@oracle ~]# docker network --help
[root@oracle ~]# docker network ls
[root@oracle ~]# docker network inspect bridge
[root@oracle ~]# ip link show
[root@oracle ~]# yum install bridge-utils -y
[root@oracle ~]# brctl show

 2、网络名称空间使用

[root@oracle ~]# rpm -q iproute  #拥有ip命令,可以操作netns
[root@oracle ~]# ip netns help
[root@oracle ~]# ip netns add ns1 #添加网络名称空间
[root@oracle ~]# ip netns add ns2
[root@oracle ~]# ip netns list    
ns2
ns1
[root@oracle ~]# ip netns exec ns1 ifconfig -a #在ns这个网络名称空间中执行命令

 创建一对虚拟网卡并且将其放到网络名称空间ns1中。

[root@oracle ~]# ip link help
[root@oracle ~]# ip link add veth1.1 type veth peer name veth1.2
[root@oracle ~]# ip link show

[root@oracle ~]# ip link set dev veth1.2 netns ns1
[root@oracle ~]# ip link show 
[root@oracle ~]# ip netns exec ns1 ifconfig -a

启动创建的虚拟网卡,并且让这对虚拟网卡通信。

[root@oracle ~]# ip netns exec ns1 ip link set dev veth1.2 name eth0 #修改名称空间ns1中的veth1.2名字为eth0
[root@oracle ~]# ip address add 10.0.1.1/24 dev veth1.1  #为本地网卡设置地址
[root@oracle ~]# ifconfig veth1.1 up
[root@oracle ~]# ip netns exec ns1 ip address add 10.0.1.2/24 dev eth0 #为ns1中的网卡设置地址
[root@oracle ~]# ip netns exec ns1 ifconfig eth0 up
[root@oracle ~]# ip netns exec ns1 ifconfig

 PS:我们也可以把一对网卡放在不同的网络名称空间,为它们配置地址并且启动,它们也是可以正常通信的。或者创建其他类型的虚拟网卡来放到不同的网络名称空间中使用。

2、docker的网络模型示例

[root@oracle ~]# docker container run --name b1 --rm -it busybox:latest #默认网络模式为bridge
[root@oracle ~]# docker container run --name b1 --rm -it --network=bridge busybox:latest  #指定网络模式为bridge
[root@oracle ~]# docker container run --name b1 --rm -it --network=none busybox:latest   #指定网络模式为none
[root@oracle ~]# docker container run --name b1 --rm -it --network=bridge -h b1.magedu.com --dns=8.8.8.8 --add-host=www.magedu.com:10.0.0.1 busybox:latest #指定网络模式,主机名,dns,添加解析到host文件

[root@oracle ~]# docker container run --name b1 --rm -it busybox:latest
[root@oracle ~]# docker container run --name b2 --network=container:b1 --rm -it busybox:latest #共享b1的IPC,Network,UTC名称空间,两个容器查看到的网卡设备,网络信息,主机名都是一样的
[root@oracle ~]# docker container run --name b2 --network=host --rm -it busybox:latest #共享宿主机的IPC,Network,UTC名称空间,查看到的网卡设备,网络信息,主机名同宿主机一样

3、暴露容器端口

[root@oracle ~]# docker run --name web1 --rm -p 80 registry.cn-hangzhou.aliyuncs.com/cmxu/httpd:v0.2-1 #将容器内的指定端口随机映射为宿主机所有地址的随意端口
[root@oracle ~]# docker container inspect web1 #可以查看到容器ip为172.17.0.2
[root@oracle ~]# curl 172.17.0.2
[root@oracle ~]# iptables -t nat -S #可以查看到转发规则
[root@oracle ~]# docker port web1 #查看某个容器的端口暴露情况

[root@oracle ~]# docker run --name web1 --rm -p 192.168.42.133::80 registry.cn-hangzhou.aliyuncs.com/cmxu/httpd:v0.2-1 #将容器指定端口80映射为宿主机192.168.42.133地址的随机一个端口
[root@oracle ~]# docker run --name web1 --rm -p 80:80 registry.cn-hangzhou.aliyuncs.com/cmxu/httpd:v0.2-1  #将容器指定端口80映射为宿主机所有地址的80端口
[root@oracle ~]# docker run --name web1 --rm -p 192.168.42.133:8082:80 registry.cn-hangzhou.aliyuncs.com/cmxu/httpd:v0.2-1  #将容器指定端口80映射为宿主机指定地址的指定端口8082

 4、修改docker0上的网络地址

[root@oracle ~]# vim /etc/docker/daemon.json 
{
  "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
  "bip": "10.10.1.2/16"
  "dns": ["10.20.1.1","10.20.1.2"]
}

配置文件中只需要加入bip即可,网关等信息docker会自动算出来,也可以自己去手动指定。dns是不能自动计算的。

5、修改docker默认监听

[root@oracle ~]# cat /etc/docker/daemon.json 
{
  "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"],
  "bip": "10.10.1.2/16",
  "hosts": ["tcp://192.168.42.133:2375", "unix:///var/run/docker.sock"]
}
[root@oracle ~]# docker -H 192.168.42.133:2375 image ls

6、创建docker网络

[root@oracle ~]# docker network create --help
[root@oracle ~]# docker network create -d bridge --subnet=172.26.0.0/24 --gateway=172.26.0.1 mybr0  #创建的网络类型为bridge,可选6种(bridge host ipvlan macvlan null overlay),但部分有环境要求。
[root@oracle ~]# docker network ls
[root@oracle ~]# docker container run --name b1 --rm -it --network=mybr0 busybox:latest

 在同一宿主机上使用不同的docker桥接网络创建两个容器,这两个容器是不能直接通信,因为docker生成的防火墙规则阻断了。在开启net.ipv4.ip_forward = 1的情况,可以处理一下防火墙规则,就可以通信了。

猜你喜欢

转载自www.cnblogs.com/cmxu/p/11624699.html