Docker第五篇(docker网络管理)
首先我们先问几个问题。
1、docker是怎么访问互联网的?
2、互联网怎么访问docker的?
3、docker之间是怎么互相访问的?
4、docker之间又是怎么隔离的?
Docker网络通讯
docker是怎么访问互联网的
我们先来看一下下面这个图,最低层是我们的宿主机上的eth0网卡,往上一层是docker0网卡(你可以理解为这是一个交换机),然后后面只要我创建一个容器就会多出来一个以veth开头的网卡。
也就是说默认情况下容器会使用docker0这个网桥,两个容器都使用这个网桥的话,就可以直接互相访问了。 然后我们docker的容器里面访问互联网的时候,其实就是从veth网卡到docker0转换,最后经过NAT转换到我们的宿主机网卡上的。也就是同属一个docker0网桥下的主机可以互相访问。
互联网怎么访问docker
1、经过前面的学习,我们第一个想到的应该是暴露端口。
下面这个命令是我们经常用的一个创建一个容器的命令,后面的-p的两个8080的含义是,暴露端口:容器端口,这样的话我们就可以直接通过宿主机的ip地址加上这个暴露端口就能访问容器里面的服务了。(这里有个误区,有人说我一个容器想暴露多个端口怎么办,首先我不建议你这么做,因为docker的基本概念就是一个容器一个进程,你可以理解为一个容器里面只跑一个单独的服务)
docker run --name tomcat1 -p 8080:8080 -d tomcat
2、有同学会讲,我宿主机有好几个网卡,我想把端口暴露到指定网卡上怎么办,如下我们直接签hostport前面再加上需要绑定网卡的ip地址就行,注意用冒号隔开。
docker run --name tomcat1 -p 192.168.8.120:8080:8080 -d tomcat
3、其它操作
将指定的容器端口映射至主机所有地址的动态端口如下,冒号前的hostport我们不加,但是具体用宿主机上的哪个端口呢,我也不知道。
docker run --name tomcat1 -p :8080 -d tomcat
A同学说上面这个命令可以更简洁,他有多个网卡,他只想暴露给指定网卡下,如下:
docker run --name tomcat1 -p 192.168.8.120::8080 -d tomcat
B同学说我这台docker宿主机上就跑了这一个docker容器,我嫌弃这映射来映射去麻烦,有办法。如下,我们直接加一个横杠大写的p,这样我们就把宿主机上的所有端口暴露给了宿主机上,除非你一个容器上运行了很多进程,否则没必要这么做。
docker run --name tomcat1 -P -d tomcat
4、查询映射关系
C同学问,我docker上太多的主机了,我也不知道他到底映射了哪些端口,我怎么看?直接使用docker port 容器名称,就可以看到当前这个容器映射了哪些端口出来了。
[root@localhost ~]# docker port tomcat1 8080/tcp -> 0.0.0.0:80 [root@localhost ~]# docker port tomcat2 8080/tcp -> 0.0.0.0:8080 [root@localhost ~]#
Docker网络模式修改
1、默认的网桥是docker0,docker0的默认IP地址是172.17.0.1。
2、那既然说了默认,肯定还是可以修改的。
docker进程网络修改
注意,docker进程网络修改了以后,凡是加入到这个网桥的容器也就跟着一起改了。注意这里是在创建网桥的时候使用的参数,不是docker run时候用的参数。
-b,--bridge=“ ”,
--bip,手动指定docker0的ip地址和子网掩码,注意我们一般不指定网桥的时候默认用的是docker0,如果docker0给两个容器的ip都是一样的,那他们就没法通讯了,所以需要此命令指定。例如:--bip 172.16.1.10/24
--dns,指定DNS,前面我们说过docker run的时候也有个--dns的参数,那个设置完了只能是
容器网络修改
docker run 使用用的参数,也就是说只作用于该容器。
--dns,给该容器配置一个DNS地址。
--net,用于指定网络通讯,有4个参数,如下:
· host模式,使用--net=host指定。 · container模式,使用--net=container:NAME_or_ID指定。 · none模式,使用--net=none指定。 · bridge模式,使用--net=bridge指定,默认设置。
默认是bridge,所以指不指定意义不大,如果是none 的话,这个容器只有lo网卡(也就是只有本地回环网卡),如果是host的话跟前面说的-P一样,把该容器的所有端口都暴露给宿主机了,最后是container的话,就相当于两个容器用的是一个网卡直接localhost就能访问到另外一个容器的端口。
修改docker0默认ip
A同学说,我老看这个172.17.0.1心里闹的慌,我要修改一下这个ip。在daemon.json里面加上后docker0网卡ip就变成这个了,然后重启docker服务,使用docker0网桥的容器也就都变成这个网段了。
常见的隔离方式
前面我们说了一些常用的通讯方式,下面我们说说容器之间怎么来隔离网络,提高安全呢。
1、默认不指定的话,容器使用的是docker0网桥,同一个网桥上容器之间是可以互相访问的。我们可以创建多个网桥,指定容器使用不同的网桥来进行容器间的隔离。
这里我们需要学习一个命令
docker network ls #查看当前主机上的所有网桥,默认有bridge、none、host,可以自行添加
创建网桥
docker network create -d 网络类型 网络空间名称(自己起名)
网络类型分为两种,一种是bridge就是我们前面用的桥接,另外一种是overlay,overlay配合第三方插件可以实现不同主机之间的容器通讯,这里我们先不说,有兴趣的通讯自己百度一下。
结论:使用不同网桥的两个容器,可以访问互联网,但是容器之间是无法访问的。
A同学问,你说的这网桥就这么直接创建了,我怎么指定网桥用的ip地址类型和网段呢,如下命令:
docker network create -d bridge --subnet "192.168.110.0/24" --gateway "192.168.110.1" lnmp
创建两个不同网段的bridge网桥
然后我们创建两个tomcat容器,分别使用lnmp和lamp网桥。
容器已经启动
我们可以看到使用两个不同的网桥的容器分别分到了自己应该分到的网段和ip,而且都能上百度,但是容器之间有进行了隔离。
跨主机通信
docker不同宿主机之间通讯分为三个方向,路由、桥接(如pipework)、overlay(如flannel)。下面我们先看看pipwork的设置方法。
环境介绍:
宿主机1:centos7.7 docker:17.03.0-ce IP:192.168.8.119
宿主机2:centos7.7 docker:17.03.0-ce IP:192.168.8.120
实验目标:
实现两台宿主机上的docker容器能够互相访问。
宿主机1:
1、设置桥接网卡,你也可以直接用命令创建。
#cd /etc/sysconfig/network-scripts/ #cp -a ifcfg-ens33 ifcfg-br0
将原有ifcfg-ens33网卡里面的ip、网关、子网掩码、dns都去掉,新加一个BRIDGE=br0即可。
TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=none DEFROUTE=yes IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no IPV6_ADDR_GEN_MODE=stable-privacy NAME=ens33 UUID=bd522766-775c-4d10-8933-9061ac412d13 DEVICE=ens33 ONBOOT=yes BRIDGE=br0
编辑ifcfg-br0网卡,这里我们要访问外网下载工具,所以网关和DNS我都加上了。
DEVICE=br0 TYPE=Bridge ONBOOT=yes BOOTPROTO=static IPADDR=192.168.8.119 NETMASK=255.255.255.0 GATEWAY=192.168.8.1 DNS1=192.168.8.1
2、下载pipework命令,启动一个测试容器,用pipework给容器单独设置和宿主机同个网段的ip。
#下载git命令 yum install -y git #下载pipework工具 git clone https://github.com/jpetazzo/pipework #将pipework命令拷贝到/usr/local/bin/下 cp pipework/pipework /usr/loca/bin/ #设置可执行权限 chmod a+x /usr/local/bin/pipework #这里我们用tomcat测试 docker pull tomcat #启动一tomcat容器,这里网络我们先设置none,后面再给他单独设置。 docker run --name tomcat --net=none -d tomcat #如下:tomcat这个名气就是我们上面启动的容器名字,ip地址是跟宿主机一个网段的ip pipework br0 tomcat 192.168.8.118/24
3、测试如下:等同于给tomcat这个容器设置了一个同宿主机一个网段的ip,这样最大的一个问题是同一个网段的ip地址有限。不适合大规模使用。
宿主机2:
1、设置桥接网卡,你也可以直接用命令创建。
#cd /etc/sysconfig/network-scripts/ #cp -a ifcfg-ens33 ifcfg-br0
将原有ifcfg-ens33网卡里面的ip、网关、子网掩码、dns都去掉,新加一个BRIDGE=br0即可。
TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=none DEFROUTE=yes IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no IPV6_ADDR_GEN_MODE=stable-privacy NAME=ens33 UUID=cc083d6b-2bf1-4ca3-b9c8-1f5f10f01b3c DEVICE=ens33 ONBOOT=yes BRIDGE=br0
编辑ifcfg-br0网卡,这里我们要访问外网下载工具,所以网关和DNS我都加上了。
DEVICE=br0 TYPE=Bridge ONBOOT=yes BOOTPROTO=static IPADDR=192.168.8.120 NETMASK=255.255.255.0 GATEWAY=192.168.8.1 DNS1=192.168.8.1
2、下载pipework命令,启动一个测试容器,用pipework给容器单独设置和宿主机同个网段的ip。
#下载git命令 yum install -y git #下载pipework工具 git clone https://github.com/jpetazzo/pipework #将pipework命令拷贝到/usr/local/bin/下 cp pipework/pipework /usr/loca/bin/ #设置可执行权限 chmod a+x /usr/local/bin/pipework #这里我们用tomcat测试 docker pull tomcat #启动一tomcat容器,这里网络我们先设置none,后面再给他单独设置。 docker run --name tomcat --net=none -d tomcat #如下:tomcat这个名气就是我们上面启动的容器名字,ip地址是跟宿主机一个网段的ip pipework br0 tomcat 192.168.8.121/24
3、测试如下:等同于给tomcat这个容器设置了一个同宿主机一个网段的ip,这样最大的一个问题是同一个网段的ip地址有限。不适合大规模使用。
总结
1、度娘说pipework不是自动执行的命令,重启失效,所以我们要给他设置开机自动运行,但是实测根本不行,重启完以后就设置的开机自启动生效不了,还是需要手动执行pipework命令。可以给容器设置--restart=always参数,让他根据docker服务器启动以后自动启动。如果已经启动容器不想重启,可以直接使用update命令。docker update --restart=always tomcat
2、这种方式适合小型环境,容器启动以后自己再挨个执行命令(可以写到一个脚本文件里面,执行一个脚本,容器的ip就都配置好了),大型环境就惨了。
3、ip地址不够用也是一个问题,同一个网段254个ip,如上2所说,这种也不可能到254容器,那只是配置ip都要疯了。
docker自带的overlay
需要注意使用overlay网络有2中模式一个是swarm模式,一个是非swarm模式,在非swarm模式下使用则需要借助服务发现第三方组件。
docker实现跨主机通信需要的网络驱动类型为overlay,但是同时还需要一个键值型的服务发现和配置共享软件,比如Zookeeper、Doozerd、Etcd、Consul等。Zookeeper、Doozerd、Etcd在架构上很类似,只提供原始的键值存储,要求程序开发人员自己提供服务发现功能,而Consul则内置了服务发现,只要用户注册服务并通过DNS或HTTP接口执行服务发现即可,同时它还具有健康检查功能。我们这里使用Consul来作为服务发现工具。先说一下环境:
宿主机1:192.168.8.119 centos7.7
宿主机2:192.168.1.120 centos7.7
docker:17.03.0-ce
关闭iptables、firewalld、selinux服务。
准备环境:
这里我们停用firewall和selinux、如果有iptables也建议先停止服务。
1、安装Consul
通常我们应该单独找一台主机,专门做Consul服务,这里我们就直接在8.119上面安装。
#wget https://releases.hashicorp.com/consul/1.7.2/consul_1.7.2_linux_386.zip #yum install -y unzip #unzip consul_1.7.2_linux_386.zip #mv consul /usr/bin/ && chmod a+x /usr/bin/consul #nohup consul agent -server -bootstrap -ui -data-dir /data/docker/consul -client=192.168.8.119 -bind=192.168.8.119 &> /var/log/consul.log
2、节点配置Dockre守护进程连接Consul,
宿主机1:去配置文件中修改内容
# vim /lib/systemd/system/docker.service
修改ExecStart参数
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store consul://192.168.8.119:8500 --cluster-advertise 192.168.8.119:2375
最后重新加载服务
systemctl daemon-reload systemctl restart docker
宿主机2:去配置文件中修改内容
# vim /lib/systemd/system/docker.service
也是修改ExecStart参数,但是注意consul://192.168.8.119:8500这个ip地址要写Consul的地址,这里指的是宿主机1的ip
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store consul://192.168.8.119:8500 --cluster-advertise 192.168.8.120:2375
最后重新加载服务
systemctl daemon-reload systemctl restart docker
3、查看consul 中的节点信息
4、在宿主机1上创建overlay网络
然后宿主机2也会自动同步这个操作。
宿主机1:
docker run --name tomcat --net=overlay -d tomcat
宿主机2:
docker run --name tomcat11 --net=overlay -d tomcat
注意:
这里我们在宿主机1上已经创建了tomcat这个名字的docker容器了,在宿主机2上创建docker容器的时候不能再叫tomcat这个名字了,docker提示已经有叫tomcat这个名字的容器了。所以我们需要改个名字。
首先创建完tomcat和tomcat11两个容器以后,宿主机1和宿主机2上都会生成一个网卡docker_gwbridge网卡。
宿主机1:
宿主机2:
最后我们分别登陆到宿主机1上的tomcat容器和宿主机2上的tomcat11容器里面看一下。
宿主机1上的tomcat容器:
宿主机2上的tomcat11容器:
补充:
前面我们看到每个宿主机上创建完overlay的容器以后,会多出来一个docker_gwbridge网卡,然后我们进入容器以后,会发现除了有一个跟docker_gwbridge同网段的ip外,也就是eth1xxx网卡,还有一个eth0xxx的网卡,这个ip地址是10.0.0.x网段的。这eth0网卡上的ip地址是用于跨主机之间互相通信的ip地址,而eth1xxx这个网卡上的ip地址是用于访问互联网和外网访问的的。
1、一定要记住这个eth0的网卡只能用户跨主机容器之间的互相访问。
2、eth1这个网卡(也就是docker_gwbridge同个网段的网卡)是用户访问互联网和被互联网访问的。这里说的能被互联网访问是要在启动容器的时候加-p参数,但是,但是,但是如下。
3、如果安装上面那样外面肯定访问不了,首先我们要加-p参数,如下:
docker run --name tomcat111 -p 8080:8080 --net=overlay -d tomcat
如果你直接运行这个启动容器命令肯定会报错。
driver failed programming external connectivity on endpoint gateway_86200ff523bb...........................................
在daemon.json里面关闭防火墙接口,如下操作
vim /etc/docker/daemon.json
重启docker服务,然后再运行启动命令 #systemctl restart docker
总结:
根据上面的演示,我们得出如下:
1、使用overlay模式进行互通的话,每个容器有两个网卡,一个是只能是不同宿主机上的容器之间通信,也就是eth0xxxxx,超过254个容器就完犊子了。
2、每个容器除了说的用户不同主机之间互访的网卡外,还会生成一个网卡,也就是eth1xxxx,这个网卡是专门用户访问互联网和被互联网访问的,
3、eth1xxxx这个访问互联网的网卡也不是直接就能被互联网访问,需要启动容器的使用用-p指定映射端口,而且前提是需要在daemon.json里面把iptables设置成false,重启docker服务才行。
4、每个容器都有两个网卡,这要是容器多了,呵呵,你细品,细细的品。