Docker 提供三种 网络驱动:bridge, macvlan 和 overlay
overlay 和 macvlan 用于创建跨主机的网络
这个网桥类似于默认网络中的 bridge
创建自定义网络命令:docker network create
$ docker network create --driver bridge --subnet 172.19.0.0/16 --gateway 172.19.0.1 mybridge_net
参数解释:
--driver bridge 表示使用桥接模式
--subnet 172.19.0.0/16 表示子网ip 可以分配 172.19.0.2 到 172.19.255.255
--gateway 172.19.0.1 表示网关
mybridge_net 表示网络名
查看
$ docker network ls
$ docker network inspect mybridge_net

使用新创建的网络创建容器
$ docker run --name=busybox_mybridge_net --net=mybridge_net -td busybox
查看
$ docker network ls
$ network inspect mybridge_net
$ ip a
$ docker run --name=busybox_mybridge_net --net=mybridge_net -td busybox
$ ip a

查看容器IP
$ docker exec -it busybox_mybridge_net ifconfig

macvlan 是在 宿主机 网卡上创建多个子网卡,并分配独立的 IP 地址和 MAC 地址,把子网卡分配给容器实例来实现实例与物理网络的直通,并同时保持容器实例的隔离性。Host 收到数据包后,则根据不同的 MAC 地址把数据包从转发给不同的子接口,在外界来看就相当于多台主机。
macvlan接口会监听并接收链路上到达本mac地址的报文,因此macvlan(除bridge外)仅能向外部网络发送报文,并接受目的为本机mac的报文。
macvlan 网络会独占物理网卡,也就是说一张物理网卡只能创建一个 macvlan 网络
根据 macvlan 子接口之间的通信模式,macvlan 有四种网络模式:
3.1、四种模式简介
3.1.1、vepa模式
在这种模式下,macvlan设备不能直接接收在同一个物理网卡的其他macvlan设备的数据包,但是其他macvlan设备可以将数据包通过物理网卡发送出去,然后通过hairpin设备返回的给其他macvlan设备,用于管理内部vm直接的流量,并且需要特殊设备支持。
创建vepa模式的网络(macvlan_mode=vepa)
$ docker network create -d macvlan --subnet=192.168.182.0/24 --gateway=192.168.182.2 -o parent=ens37 -o macvlan_mode=vepa vepamv
使用上述网络运行2个容器
$ docker run -itd --net=vepamv --ip=192.168.182.222 --name=macvlan-vepa-1 busybox /bin/sh
$ docker run -itd --net=vepamv --ip=192.168.182.223 --name=macvlan-vepa-2 busybox /bin/sh
查看网络信息,可以看到驱动类型为macvlan,macvlan模型为vepa,两个网卡有独立的mac地址,底层物理网卡为ens37
$ docker network inspect vepamv

在macvlan-vepa-1中ping macvlan-vepa-2发现无法ping通,因为本地环境上并没有开启hairpin模式的交换机或路由器,报文发送到链路上之后无法返回来。即无法在internal内部进行报文传输
$ docker exec -it macvlan-vepa-1 ping 192.168.182.223

但在external network的机器(宿主机:192.168.182.130)是可以直接访问该容器的(首先该容器的IP属于external network)

3.1.2、passthru模式
这种模式,只允许单个子接口连接主接口,且必须设置成混杂模式,一般用于子接口桥接和创建 VLAN 子接口的场景。
3.1.3、private模式
隔离功能比VPEA更强,阻断了广播和组播,即使交换机开启hairpin也无法通信。
3.1.4、bridge模式
在这种模式下,寄生在同一个物理设备的macvlan设备可以直接通讯,不需要外接的hairpin设备帮助,使用如下的命令创建一个bridge的macvlan网络。
3.2、相同 macvlan 网络之间的通信原理

1)准备两台机器
host1:192.168.182.130 ens33
host2:192.168.182.152 bond0
2)创建两台宿主机上macvlan
# 在host1创建macvlan网络
$ docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=ens33 mac1
# 在192.168.182.152上创建macvlan网络
$ docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.11.1 -o parent=bond0 mac1
# 查看
$ docker network ls
参数解释
-d/--driver 指定 Docker 网络 driver
--subnet 指定 macvlan 网络所在的网络
--gateway 指定网关
-o parent 指定用来分配 macvlan 网络的物理网卡
3)使用上面创建的macvlan网络创建容器
# 在host1上创建以macvlan网络的容器
$ docker run -itd --name c1 --ip=172.16.10.2 --network mac1 busybox
# 在host2上创建macvlan网络
$ docker run -itd --name c2 --ip=172.16.10.3 --network mac1 busybox
--ip 指定容器 c1 使用的 IP,这样做的目的是防止自动分配,造成 IP 冲突
--network 指定 macvlan 网络
4)验证,在 host1 c1 中 ping host2 c2
$ docker exec c1 ping -c 2 172.16.10.3

3.2、不同 macvlan 网络之间的通信
准备三台机器(Centos8),桥接模式
host1:
ens33(NAT) 192.168.182.153
ens34(桥接) 192.168.0.110
host2:
ens33(NAT) 192.168.182.154
ens34(桥接) 192.168.0.111
host3:
ens33(NAT) 192.168.182.155
ens34(桥接) 192.168.0.112
第一步:先实现相同macvlan网络之间的通信
接下来,我们来看看相同 macvlan 网络之间的连通性,搭建以下的拓扑环境:

由于 macvlan 网络会独占物理网卡,也就是说一张物理网卡只能创建一个 macvlan 网络,如果我们想创建多个 macvlan 网络就得用多张网卡。
好在 macvlan 网络也是支持 VLAN 子接口的,所以,我们可以通过 VLAN技术将一个网口划分出多个子网口,这样就可以基于子网口来创建 macvlan 网络了,下面是具体的创建过程。
1)开启混杂模式
$ ip link set ens34 promisc on
2)首先分别在两台主机上将物理网口 ens33创建出两个 VLAN 子接口。
$ ip link add link ens34 name ens34.10 type vlan id 100
$ ip link add link ens34 name ens34.20 type vlan id 101
# 启动子网卡
$ ip link set ens34.10 up
$ ip link set ens34.20 up
3)分别在 host1 和 host2 上基于两个 VLAN 子接口创建 2 个 macvlan 网络,macvlan10 和 macvlan20。
$ docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=ens34.10 mac_net10
$ docker network create -d macvlan --subnet=172.16.20.0/24 --gateway=172.16.20.1 -o parent=ens34.20 mac_net20
4)分别在 host1 和 host2 上运行容器,并指定不同的 macvlan 网络。
# host1
$ docker run -itd --name bbox1 --ip=172.16.10.10 --network mac_net10 busybox
$ docker run -itd --name bbox2 --ip=172.16.20.10 --network mac_net20 busybox
# host2
$ docker run -itd --name bbox3 --ip=172.16.10.11 --network mac_net10 busybox
$ docker run -itd --name bbox4 --ip=172.16.20.11 --network mac_net20 busybox
通过验证,bbox1 和 bbox3,bbox2 和 bbox4 在同一 macvlan 网络下,互相可以 ping 通,bbox1 和 bbox2,bbox1 和 bbox4 在不同的 macvlan 网络下,互相 ping 不通。
$ docker exec -it bbox1 ping 172.16.10.11
$ docker exec -it bbox2 ping 172.16.20.11
$ docker exec -it bbox1 ping 172.16.20.10
$ docker exec -it bbox1 ping 172.16.20.11

注意:如果你是vmware环境的话,由于VMware虚拟机的原因,必须将两台主机默认的NAT模式修改为桥接模式才能够正常通信
第二步:不同macvlan网络之间的通信实现
通过上面验证同一个二层macvlan网络是可以互通,但是不通macvlan网络是不通的,如果需要通,则需要通过三层的路由,我们这就来验证下。
就加一台 host3,以下操作都是在host3上操作的,通过打开 ip_forward 把它改造成一台路由器,用来打通不同 macvlan 网络,大概的图示如下所示:

跨主机通信已经不从虚线走了,都从host3走,因为host3充当着两个maclvan的网关,当然也是路由器的角色。
1)首先对 host3 执行 sysctl -w net.ipv4.ip_forward=1 打开路由开关。
$ sysctl -w net.ipv4.ip_forward=1
#查看
$ sysctl net.ipv4.ip_forward
$ cat /proc/sys/net/ipv4/ip_forward
2)然后host3创建两个 VLAN 子接口,一个作为 macvlan 网络 mac10 的网关,一个作为 mac20 的网关。
# host1,host2创建子接口,注意name和id必须要跟上面的两台机器一样,要不然会网络不通
$ ip link add link ens34 name ens34.100 type vlan id 100
$ ip link add link ens34 name ens34.200 type vlan id 101
# 对 vlan 子接口配置IP充当网关 IP 并启用
$ ip addr add 172.16.10.1/24 dev ens34.100
$ ip link set ens34.100 up
$ ip addr add 172.16.20.1/24 dev ens34.200
$ ip link set ens34.200 up
3)这样之后再从 bbox1 和 bbox2,bbox1 和 bbox4,就可以 ping 通了。
$ docker exec -it bbox1 ping 172.16.20.10
$ docker exec -it bbox1 ping 172.16.20.11

可能有些系统做了安全限制,可能 ping 不通,这时候可以添加以下 iptables 规则,目的是让系统能够转发不通 VLAN 的数据包。我这里是没加也是可以通的。
$ iptables -t nat -A POSTROUTING -o ens34.10 -j MASQUERADE
$ iptables -t nat -A POSTROUTING -o ens34.20 -j MASQUERADE
$ iptables -A FORWARD -i ens34.10 -o ens34.20 -m state --state RELATED,ESTABLISHED -j ACCEPT
$ iptables -A FORWARD -i ens34.20 -o ens34.10 -m state --state RELATED,ESTABLISHED -j ACCEPT
$ iptables -A FORWARD -i ens34.10 -o ens34.20 -j ACCEPT
$ iptables -A FORWARD -i ens34.20 -o ens34.10 -j ACCEPT
缺点:不能自动校验ip冲突,得人为区分,只能容器之间访问,而且无法访问到外网,overlay可以补足
4.1、介绍
Overlay网络模式,在多个docker daemon 主机之间穿件一个分布式的网络,该网络(overlay)位于docker主机层次之上,允许容器(同一集群服务的容器)之间加密通讯,因此,docker需要处理每一个主机(docker daemon)和每个分布的容器之间的包路由。
每当初始化一个集群(swarm)或者添加一个docker主机到集群时,则在该主机上会自动创建两个网络(ingress和docker_gwbridge),但是swarm集群需要三个网络,还有一个自定义overlay网络。
# 查看docker网络
$ docker network ls
# 在192.168.0.113机器上初始化一个swarm集群
$ docker swarm init --advertise-addr 192.168.0.113
# 再查看docker网络
$ docker network ls

$ docker network create -d overlay my-overlay

4.2、overlay netwrok 操作
1)环境
host1 192.168.0.113 ens33 centos8
host1 192.168.0.114 ens33 centos8
2)准备工作
放通这三个端口(所有节点都执行)
# 放通2377/tcp,7946/udp,4789/udp端口
$ firewall-cmd --zone=public --add-port=2377/tcp --permanent
$ firewall-cmd --zone=public --add-port=7946/tcp --permanent
$ firewall-cmd --zone=public --add-port=7946/udp --permanent
$ firewall-cmd --zone=public --add-port=4789/udp --permanent
# 重新加载生效
$ firewall-cmd --reload
# 查看
$ firewall-cmd --list-ports
清理上面创建的swarm集群和创建出来的网络
# 删除集群节点,因为上面初始化了,相对于删除了集群了,删除集群后会自动把swarm网络删掉,所以这里只需要手动删除docker_gwbridge。
$ docker swarm leave -f
$ docker network rm docker_gwbridge

以下操作在host1上执行
3)初始化一个swarm集群
$ docker swarm init --advertise-addr 192.168.0.113
# 查看集群
$ docker node ls
# 查看网络
$ docker network ls

3)创建 overlay network
$ docker network create --attachable -d overlay my-overlay
# 或者指定子网,不指定会随机生成一个子网
$ docker network create -d overlay --subnet=10.0.1.0/24 --gateway=10.0.1.1 --attachable my-overlay
# 查看
$ docker network inspect my-overlay

--attachable:允许集群服务间的容器交互连接或者独立的容器之间能够连接。swarm在设计之初是为了service(一组container)而服务的,因此通过swarm创建的overlay网络在一开始并不支持单独的container加入其中。但是在docker1.13, 我们可以通过“--attach” 参数声明当前创建的overlay网络可以被container直接加入。
4)把host2加入集群
# 在host1上执行,查看加入命令
$ docker swarm join-token worker
# 在host2上执行,把host2加入到swarm集群
$ docker swarm join --token SWMTKN-1-54jufnlpeihtnedmpsexqvayz2jbm8f78ijlt4pik7huie9bmr-djfn6m3lz143e0fyjbcocnqhl 192.168.0.113:2377
5)查看swarm集群
$ docker node ls

6)在host1 manager节点上创建一个容器busybox1,指定上面创建的overlay网络
$ docker run -itd --name=busybox1 --network=my-overlay busybox /bin/sh
再次查看网络,可以发现有了容器的IP及LB IP
$ docker network inspect my-overlay

7)在host2 worker节点上创建一个容器busybox2:
$ docker run -itd --name=busybox2 --network=my-overlay busybox /bin/sh
# 查看网络
$ docker network inspect my-overlay

8)在上面刚创建的2个容器内互相PING对方做测试

再ping外网

从上图看,既可以ping内网,也可以ping外网,得益于每个容器有两块网卡,一块内网通信,一块直接桥接到docker_gwbridge出外网。
根据上面讲解和实验,容器间的网络架构图如下:

其实从上图看,可能有朋友会发现,为啥有vxlan的标注,因为vxlan才是实体,overlay只是网络模型;一句话就是vxlan是overlay网络的一种实现,如果不清楚vxlan的,可以看这里。
其实可以查看my-overlay网络的具体信息,里面会有vxlan的一些参数
$ docker network inspect my-overlay

我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano
我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是