博文大纲:
1、前言
2、Docker的原生网络
3、自定义bridge网络
4、实现docker跨主机通讯
5、使外网能够访问容器的方法nginx
因为docker技术的火爆,致使如今愈来愈多的企业都在使用docker这种虚拟化技术。企业中使用docker这种虚拟化技术,其目的就是为了让docker中的容器对外提供服务。所以,咱们必须深刻了解一下docker的网络知识,以知足更高的网络需求。web
当你安装Docker时,它会自动建立三个网络。以下:docker
[root@localhost ~]# docker network ls //查看docker的默认网络 NETWORK ID NAME DRIVER SCOPE a38bd52b4cec bridge bridge local 624b3ba70637 host host local 62f80646f707 none null local
Docker内置这三个网络,运行容器时,你可使用该“--network”选项来指定容器应链接到哪些网络。若是没有指定则默认使用bridge模式。bootstrap
好比:vim
host模式:使用 --net=host 指定; none模式:使用 --net=none 指定; bridge模式:使用 --net=bridge 指定(默认设置);
下面详细介绍一下这几种网络模式:浏览器
虽然docker模式提供三种网络模式,但实际上是有四种网络模式的!安全
若是启动容器时使用host模式,那么这个容器将不会得到一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出本身的网卡,配置本身的IP等,而是使用宿主机的IP和端口。 服务器
使用场景:网络
因为网络配置与docker宿主机彻底同样,性能较好,可是不便之处就是灵活性不高,容易和宿主机出现端口冲突的问题。最好是单个容器时使用,通常状况下不建议使用。tcp
建立使用host网络模式的容器示例:
[root@localhost ~]# docker run -it --name host --network host busybox:latest //使用busybox镜像建立一个名为host的容器,网络采用host模式 / # ip a //进入容器后能够看出容器中的网络与docker主机的网络如出一辙 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 00:0c:29:66:72:13 brd ff:ff:ff:ff:ff:ff inet 192.168.1.1/24 brd 192.168.1.255 scope global ens33 valid_lft forever preferred_lft forever inet6 fe80::9f3:b94e:5f5d:8070/64 scope link valid_lft forever preferred_lft forever 3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue qlen 1000 link/ether 52:54:00:e1:82:15 brd ff:ff:ff:ff:ff:ff inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0 valid_lft forever preferred_lft forever 4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 qlen 1000 link/ether 52:54:00:e1:82:15 brd ff:ff:ff:ff:ff:ff 5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue link/ether 02:42:3c:06:f8:1d brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever
在none模式下,Docker容器拥有本身的Network Namespace,可是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。须要咱们本身为Docker容器添加网卡、配置IP等。
使用场景:
none模式被称为隔离的网络,隔离便意味着安全,不能与外部通讯,一样外部也不能够访问到使用none模式的容器,使用这种网络模式的容器能够运行于关于安全防面的验证码、校验码等服务。
通常用于对安全性要求较高的场景中!
建立使用none网络模式的容器示例:
[root@localhost ~]# docker run -it --name none --network none busybox:latest //使用busybox镜像建立一个名为none的容器,网络采用none模式 / # ip a //能够看到容器中只有一个lo网卡 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever
bridge模式是Docker默认的网络设置,此模式会为每个容器分配Network Namespace、设置IP等,并将一个主机上的Docker容器链接到一个虚拟网卡上。当Docker server启动时,会在主机上建立一个名为docker0的虚拟网桥,此主机上启动的Docker容器会链接到这个虚拟网桥上。虚拟网桥的工做方式和物理交换机相似,这样主机上的全部容器就经过交换机连在了一个二层网络中。接下来就要为容器分配IP了,Docker会从RFC1918所定义的私有IP网段中,选择一个和宿主机不一样的IP地址和子网分配给docker0,链接到docker0的容器就从这个子网中选择一个未占用的IP使用。如通常Docker会使用172.17.0.0/16这个网段,并将172.17.0.1/16分配给docker0网桥。
[root@localhost ~]# ifconfig docker0 docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:3c:06:f8:1d txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 [root@localhost ~]# brctl show //查看桥接网络 bridge name bridge id STP enabled interfaces docker0 8000.02423c06f81d no //若是没有建立桥接模式的容器,默认是空的。
建立使用bridge网络模式的容器示例:
[root@localhost ~]# docker run -itd --name bridge busybox:latest /bin/sh //建立一个名为bridge的容器,若是没有指定网络模式,默认即是bridge模式 [root@localhost ~]# docker exec -it bridge /bin/sh //进入bridge容器中 / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 6: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever //能够看出eth0@if9这块虚拟网卡上的地址与docker宿主机的docker0网络属于同一网段 [root@localhost ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.02423c06f81d no veth811d20c //能够看到桥接模式的接口下出现了一个新的接口,当建立一个容器便会出现一个接口 //这个接口即是容器在docker宿主机建立一个虚拟网卡,用于容器与docker通讯 [root@localhost ~]# ifconfig veth811d20c //查看这个虚拟网卡是否存在 veth811d20c: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::c035:95ff:febf:978b prefixlen 64 scopeid 0x20<link> ether c2:35:95:bf:97:8b txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 648 (648.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
当使用bridge网络模式,docker的工做步骤大体为:
(1)在主机上建立一对虚拟网卡veth pair设备。veth设备老是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另外一个设备出来。所以,veth设备经常使用来链接两个网络设备;
(2)Docker将veth pair设备的一端放在新建立的容器中,并命名为eth0。另外一端放在主机中,以veth811d20c这样相似的名字命名,并将这个网络设备加入到docker0网桥中,能够经过brctl show命令查看(上述实例已经验证);
(3)从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关;
这个模式指定新建立的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新建立的容器不会建立本身的网卡,配置本身的IP,而是和一个指定的容器共享IP、端口范围等。一样,两个容器除了网络方面,其余的如文件系统、进程列表等仍是隔离的。两个容器的进程能够经过lo网卡设备通讯。
建立使用container网络模式的容器示例:
[root@localhost ~]# docker run -it --name container --network container:a172b832b531 busybox:latest //a172b832b531是bridge容器的ID号 / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever //能够看出container容器的IP地址与bridge容器的IP地址如出一辙
关于这四种网络模式推荐使用默认的bridge网络模式!
细心一点能够发现,建立的容器默认状况IP地址为172.17.0.0/16网段,那么咱们可不能够自定义一个网段供容器使用呢?答案确定是能够的,方法以下:
[root@localhost ~]# docker network create -d bridge my_net //建立一个桥接网络,名称为my_net,若是没有指定网段,默认是172.18.0.0/16,按docker0的网段自动递增 [root@localhost ~]# docker network ls //查看docker支持的网络类型 NETWORK ID NAME DRIVER SCOPE 9fba9dc3d2b6 bridge bridge local 624b3ba70637 host host local 74544573aa67 my_net bridge local 62f80646f707 none null local //能够看出,刚才建立的my_net已经出如今列表中 [root@localhost ~]# docker run -itd --name test1 --network my_net busybox:latest /bin/sh [root@localhost ~]# docker run -itd --name test2 --network my_net busybox:latest /bin/sh //使用刚才建立的网络模式建立两个容器 [root@localhost ~]# docker exec -it test1 /bin/sh //进入test1 / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 11: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0 valid_lft forever preferred_lft forever //查看其IP地址,发现确实是172.18.0.0/16网段的 / # ping test2 //测试经过容器名称ping test2容器 PING test2 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.079 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.175 ms [root@localhost ~]# ifconfig br-74544573aa67 //这张虚拟网卡就是咱们建立my_net网络时产生的 br-74544573aa67: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255 inet6 fe80::42:50ff:fec2:7657 prefixlen 64 scopeid 0x20<link> ether 02:42:50:c2:76:57 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 //经过IP地址网段就可看出
自定义网络的优势:
- 能够经过容器的名称进行通讯;
- 自定了ContainerDNSserver功能;
以上方法按照默认的方式建立一个桥接模式的网络,能够发现网段地址并非咱们自定义的。
接下来咱们经过指定具体网段的方式建立网卡。方法以下:
[root@localhost ~]# docker network create -d bridge --subnet 200.0.0.0/24 --gateway 200.0.0.1 my_net2 //自定义网络模式的地址时,必需要明确指定其IP网段及网关信息 [root@localhost ~]# ifconfig br-0ca6770b4a10 //这张虚拟网卡即是咱们建立my_net2网络时产生的 br-0ca6770b4a10: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 200.0.0.1 netmask 255.255.255.0 broadcast 200.0.0.255 ether 02:42:05:ba:8b:fc txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 //能够看出其IP地址就是咱们指定的IP地址 [root@localhost ~]# docker run -itd --name test3 --network my_net2 --ip 200.0.0.100 busybox:latest [root@localhost ~]# docker run -itd --name test4 --network my_net2 --ip 200.0.0.200 busybox:latest //基于刚才建立的网络建立出两个容器并指定其固定的IP地址 [root@localhost ~]# docker exec -it test3 /bin/sh //进入test3容器 / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 16: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:c8:00:00:64 brd ff:ff:ff:ff:ff:ff inet 200.0.0.100/24 brd 200.0.0.255 scope global eth0 valid_lft forever preferred_lft forever //发现其IP地址确实咱们刚才指定的IP地址 / # ping test4 //测试发现确实是能够和test4通讯的 PING test4 (200.0.0.200): 56 data bytes 64 bytes from 200.0.0.200: seq=0 ttl=64 time=0.156 ms 64 bytes from 200.0.0.200: seq=1 ttl=64 time=0.178 ms / # ping test1 ping: bad address 'test1' //发现没法与第一次建立的网络进行通讯
使用相同的网络建立的容器是能够相互通讯的,可是发现没法与其余容器进行通讯,这主要是由于iptables规则的缘由,建立docker网络时,iptables规则就会随着自动添加的。
举例说:尝试把iptables规则清空,是能够实现咱们想要的效果的。可是这种命令的做用不亚于“rm -rf /*”,显然在现实环境中是不可使用的!
那么就须要使用下面的方法来实现了,方法以下:
[root@localhost ~]# docker network connect my_net2 test1 //这条命令就是在test1容器中添加一块虚拟网卡(my_net2分配的) [root@localhost ~]# docker exec -it test1 /bin/sh / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 11: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0 valid_lft forever preferred_lft forever 20: eth1@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:c8:00:00:02 brd ff:ff:ff:ff:ff:ff inet 200.0.0.2/24 brd 200.0.0.255 scope global eth1 valid_lft forever preferred_lft forever //能够查询到确实多了一块虚拟网卡,网段确实和my_net2属于同一网段 / # ping test3 PING test3 (200.0.0.100): 56 data bytes 64 bytes from 200.0.0.100: seq=0 ttl=64 time=0.171 ms 64 bytes from 200.0.0.100: seq=1 ttl=64 time=0.237 ms ^C --- test3 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.171/0.204/0.237 ms / # ping test4 PING test4 (200.0.0.200): 56 data bytes 64 bytes from 200.0.0.200: seq=0 ttl=64 time=0.097 ms ^C --- test4 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 0.097/0.097/0.097 ms //测试与test三、test4通讯,通讯正常
注意:此时test2容器并不能够与test三、test4进行通讯!若是须要其通讯,还需给test2添加虚拟my_net2网卡地址(使用案例中的命令便可)!
注意:
- 容器之间可使用容器名进行通讯,但前提必须是使用自定义网络,好比案例中建立的my_net、my_net2;
- 若是在建立自定义网络时,指定了该网络的网段,那么使用此时的容器也能够指定容器的IP地址,若没有指定该网络的网段,则不可指定容器的IP地址;
本篇博文实现docker跨主机通讯主要是使用consul服务的特性!
consul:是一个服务网格(微服务间的 TCP/IP,负责服务之间的网络调用、限流、熔断和监控)解决方案,它是一个一个分布式的,高度可用的系统,并且开发使用都很简便。它提供了一个功能齐全的控制平面,主要特色是:服务发现、健康检查、键值存储、安全服务通讯、多数据中心。
经过一个小案例来验证consul服务的特性!
(1)关闭防火墙与SELinux(实验环境);
(2)更改主机名,避免发生冲突;
(1)Docker1
[root@Docker1 ~]# docker pull progrium/consul //下载consul镜像 [root@Docker1 ~]# docker run -d -p 8500:8500 -h consul --name consul --restart=always progrium/consul -server -bootstrap //-d:后台运行; //-p:将容器中的8500端口映射到宿主机的8500端口; //-h:表示consul容器的主机名; //--name:表示运行的容器名; //--restart=always:随docker服务的启动而启动; //-server -bootstrap:添加这两个选项,则表示在群集环境中可使其以master的身份出现; [root@Docker1 ~]# netstat -anpt | grep 8500 tcp6 0 0 :::8500 :::* LISTEN 2442/docker-proxy //肯定其8500端口正在监听
(2)Docker2
[root@Docker2 ~]# vim /usr/lib/systemd/system/docker.service //编写Docker的主配置文件 13 ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://192.168.1.1:8500 --cluster-advertise=ens33:2376 //在第13行上本来的基础添加以上内容,各个配置项含义以下: # /var/run/docker.sock:Docker的一个套接字; # “ -H tcp://0.0.0.0:2376 ” :使用本机的tcp2376端口; # “ --cluster-store=consul://192.168.1.1:8500”:指定运行着consul服务的docker服务器IP及端口; # “ --cluster-advertise=ens33:2376”:从本机的ens33网卡经过2376端口搜集网络信息,存储在consul上 [root@Docker2 ~]# systemctl daemon-reload [root@Docker2 ~]# systemctl restart docker //从新启动docker服务
(3)Docker3
Docker3与Docker2的操做就是如出一辙的,因此这里就很少作解释了!
[root@Docker3 ~]# vim /usr/lib/systemd/system/docker.service 13 ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://192.168.1.1:8500 --cluster-advertise=ens33:2376 [root@Docker3 ~]# systemctl daemon-reload [root@Docker3 ~]# systemctl restart docker
(4)使用浏览器访问consul服务的web页面
如图:
(5)将Docker1服务器也加入到consul群集
[root@Docker1 ~]# vim /usr/lib/systemd/system/docker.service 13 ExecStart=/usr/bin/dockerd -H unix:////var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://192.168.1.1:8500 --cluster-advertise=ens33:2376 [root@Docker1 ~]# systemctl daemon-reload [root@Docker1 ~]# systemctl restart docker //解释上面都已经解释的很清楚,这里就不作解释了
再次访问consul的web页面,如图:
若是在此过程当中,访问web页面若是出现“500”的错误页面,将运行consul服务的容器删除从新创新便可!
(6)建立一个 overlay网络
[root@Docker1 ~]# docker network create -d overlay my_olay //建立一个名为my_olay的voerlay网络 //以上操做无论在那台docker主机上操做均可以 [root@Docker1 ~]# docker network create -d overlay --subnet 200.0.0.0/24 --gateway 200.0.0.1 lv_olay //也能够在建立overlay网卡时,指定其IP网段及网关 [root@Docker1 ~]# docker network ls //查看docker所支持的网络
并且在另外两台docker服务器上也可看到,自行验证!
在docker 1上建立的网络,能够看到其SPOCE(范围)定义的是global(全局),那么这就意味着加入consul这个服务群集的其余docker服务器也能够看到这张网卡!
若是在建立网卡时,没有指定其网段,则默认是10.0.0.0网段,因为是自定义网络,因此知足自定义网络的特征(好比支持容器之间的通讯)!
(7)在不一样的docker服务器各自建立一个容器,验证是否能够通讯!
[root@Docker1 ~]# docker run -itd --name t1 --network lv_olay --ip 200.0.0.10 busybox:latest //在docker1服务器上建立一个名为t1的容器并指定其IP地址 [root@Docker2 ~]# docker run -itd --name t2 --network lv_olay --ip 200.0.0.20 busybox:latest //在docker2上建立一个容器并指定IP地址 [root@Docker3 ~]# docker run -itd --name t3 --network lv_olay --ip 200.0.0.30 busybox:latest //在docker3上建立一个容器并指定IP地址 [root@Docker1 ~]# docker exec -it t1 /bin/sh //随便在一台docker服务器上进入其建立的容器中,进行测试
如图:
(1)手动指定映射端口
[root@localhost ~]# docker run -itd --name web1 -p 90:80 nginx //将一个容器的nginx服务映射到宿主机的90端口
(2)随机映射端口[root@localhost ~]# docker run -itd --name web2 -p 80 nginx //若是-p以后只有一个端口,则是容器中的端口(宿主机会随机映射一个端口)从32768端口开始
(3)将容器中的端口所有映射到宿主机上
[root@localhost ~]# docker run -itd --name web4 -P nginx //注意:大写的P //从宿主机随机映射端口到容器,容器内全部暴露的端口,都会一一映射
以上操做,我的验证没有问题,这里就不截图示范了!
—————————本文到此结束,感谢观看—————————