目录:
1. docker网络通讯的模式
2. docker网络模式的修改
3. 常见隔离方式
一. docker网络通讯的模式
docker 网络通讯的几种形式
1. 容器与容器之间
2. 容器访问外部网络
3. 外部网络访问容器
1.1 容器和容器之间如何进行通讯的?
1. 每台机器上都有一个网卡,有的甚至有两个网卡 ,ETHD 10.1.1.10/8就表示一个网卡
2. docker启动以后,会出现一个docker0,我们可以通过ifconfig来查看
我们发现, 有一个docker0, docker0是什么?我们可以将其理解为交换机,术语称之为网桥, 那交换机有什么作用?交换不同容器之间的数据, 让数据间可以交流。
交换机一旦创建以后, 就会创建一个叫namespace的东西,名字叫做network namespace. 全名叫做网络命名空间.也就是上图中蓝色方框VethX,不同的网络命名空间会形成相互隔离,一端固定在容器内容, 成为虚拟网卡, 另一端固定在本机。
进入到容器查看ip a,可以看到eth0的网卡
在本机会生成一个类似vethe1abf09@if26的网卡与容器中的网卡相对应。
只要多一个容器就会多一个veth。也就是说一端在容器里,另一端在本机里,作为连通的作用。 并且, 网络命名空间会将不同的网络隔离开来,各用个的。这样就实现了隔离,以及怎样与本机进行交互。这样,容器和容器之间就可以通讯了。 这解决的是容器和容器间进行通讯。 这是通过docker0网桥解决的
1.2. 容器如何访问外部网络
iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -o docker0 -j MASQUERADE
这是一个典型的SNAT转换, 这种方式是通过TNAT的方式实现的
1.3 外部网络如何访问容器
docker run -d -p 80:80 apache
外部网络访问容器只需加上-p 80:80, 就会实现下面两个操作。
iptables -t nat -A POSTROUTING -m addrtype --dst-type LOCAL -j DOCKER
iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80
这种方式是通过DNAT来实现的
二. 网络模式的修改
docker启动以后,默认的网桥是docker0,默认的ip地址172.0.0.1, 我们能不能修改默认的网桥和ip地址呢?接下来就看看有哪些值能被我们修改
1. docker进程网络修改参数
docker进程修改,后面的容器都会跟着被修改. 相当于是主程序修改,相应的容器都会跟着修改
也就是说,我们的网桥是docker0,如果你想要吧网桥改成docker1,怎么改呢?设置一个参数--bridge="docker1"就可以了
-
--bip 指定docker0的ip和掩码,使用标准的CIDR形式,如10.10.10.10/24. 其中24表示的就是子网掩码255.255.255.0. 这是一个默认的表达方式
-
--dns 配置容器的dns,在启动docker进程的时候添加,所有容器都会生效
2. 容器网络的修改
--dns 用于指定启动的容器的DNS. 只在启动的容器生效
--net 用于指定容器的网络通讯方式,有以下四个值
1. bridge: 网桥方式,也是docker的默认方式. 也就是通过网桥进行数据通讯,并且是隔离
2. none: 没有任何的ip地址. 如果启动容器的时候,使用了--net="none",通过ip a查看容器的网络,发现没有连接网络的信息. 也就是说不能和外界联通.
比如: 我们启动一个tomcat
docker run -it --name tomcat11 --net=none tomcat9 /bin/bash
我们在执行ip a查看网络情况. 我们发现没有外网连接.
一个容器,都不能上网了,那还有什么用呢?
有些容器没必要有网络. 比如:有些容器是做计算的,这种计算完把结果放在本地了,他不需要有网络,有了网络反而不安全了.只能自己跟自己通讯.
3. container: 使用其他容器的网络栈,Docker容器会加入其他容器的network namespace. 如果使用同一个网络栈,比如:一个容器是Nginx,另一个容器是MysqL. Nginx就可以向在本地一样访问3306端口了. 这样安全性就差了,但在有些环境,就是要求要这种
4. host: 表示容器使用host的网络,没有自己独立的网络,容器可以完全访问host的网络,
我们启动一个tomcat:
docker run --name tomcat11 --net=host -d tomcat:v1.0
运行这个容器之前,要确保本机的8080端口没有被使用
然后在容器里运行curl http://locahost:8080
再在虚拟机中运行curl http://localhost:8080
我们发现,他们访问的内容是一样,容器启动的时候没有使用-p 进行端口映射,为什么能访问呢?
因为容器使用的host主机的网络,相当于容器启动了8080端口,默认主机也有这个端口,所以可以直接访问.
3. 暴露端口
-p/-P 选项的使用
-
-p :<ContainerPort> 将制定的容器端口映射到主机所有地址的一个动态端口.
- 意思是: 容器端口有了,你要访问那个主机端口,不确定,这个是随机的
- -p <HostPort>:<ContainerPort> 容器的指定端口映射到主机的指定端口 (最常用)
- -p <IP>::<ContainerPort> 映射到指定的主机的IP的动态端口
- -p <IP>:<HostPort>:<ContainerPort> 映射到指定主机ip的主机端口 (最常用)
- -P,暴露需要的所有端口
docker port 容器ID,可以查看容器当前的端口映射关系
4. 自定义docker0网桥的网络地址
/etc/docker/daemon.json文件
{
'bip':"192.168.1.5/24"
"final-cidr":"10.20.0.0/36"
"default-gateway":"10.20.1.1"
"dns":["10.20.1.1","10.20.1.3"]
}
三. 常见的隔离方式
我们先来看一种情况.
我在192.168.198.142虚拟机上启动两个docker容器
docker run -it --name tomcat1 tomcat9 /bin/bash
docker run -it --name tomcat2 tomcat9 /bin/bash
查看两个容器的ip
tomcat1的ip是172.17.0.2,tomcat2的ip是172.17.0.3.
那么我们在tomcat1中pingtomcat2的ip能不能ping通呢?
ping 172.17.0.3
没问题,我们看到,确实是成功了. 这说明什么?
这说明,如果容器1和容器2相互之间可以通过ip进行访问.
那么,如果我不想让他们之间相互访问,怎么办呢? 这就是容器和容器之间网络隔离
3.1 容器间网络隔离
所谓容器间网络隔离,指的是容器和容器之间网络不通,也就是ping不通.既然ping不通,那么相互之间就不能访问了. 但是依然是可以和主机相互访问的.
下面看几个命令:
docker network ls
我们看到,有一个网络是默认的bridge网络. 之所以上面两个tomcat容器之间可以相互访问,原因是: 他们使用的是同一个网段. 如果我们想实现隔离,让他们处于不同的网段就可以了.
我们可以通过下面的命令创建新的网段
docker network create -d 网络类型 网络名词
网络类型有两种
overlay network---主要用在不同的主机中的容器可以互相通信,但是需要借助其他一些软件去实现
bridge network---网桥.
下面我们就使用这种网桥来创建两个新的网络
docker network create -d bridge lamp
docker network create -d bridge lnmp
查看当前已有的网络
通过查看本机的ip,我们看到多了两个网络
原来只有172.17.0.1网络,现在增加了172.18.0.1/16 和 172.19.0.1/16
接下来,我们使用新的网络新建两个容器
新建一个容器tomcat1,设置他的网络使用lamp,他的网段是172.18.0.1
docker run -it --name tomcat1 --network=lamp tomcat9 /bin/bash
进入到容器以后,输入ip a查看容器的ip地址
我们看到容器的ip地址是172.18.0.2
在新建一个容器2,设置他的网络使用lnmp,他的网段是172.19.0.1
docker run -it --name tomcat2 --network=lnmp tomcat9 /bin/bash
进入到容器,查看容器的ip
我们看到容器2的ip地址是172.19.0.2
现在这两个容器处在不同的网段,处于不同的两个网段,他们之间肯定是ping不通的.
在容器1中ping 172.19.0.2,ping不通
反之,在容器2ping容器1的ip也ping不通. 这样就实现了容器将网络的隔离
我们之前,搭建的harbor仓库,我们可以看一下这台服务的已经启动的docker网络
虚拟机:
192.168.198.143 查询docker网络命令 docker network ls
我们看到有一个名字叫做harbor_harbor的网络. 采用的network方式是bridge
3.2 如何让两台主机的两个容器之间可以通讯?
比如: 让ip是192.168.198.142虚拟机上的docker容器能够和192.168.198.143虚拟机上的docker容器进行通讯?
这里需要我们自己去指定网桥.
下面我们要搭建一个网桥,这个网桥和外界具有真正的通讯能力. 什么叫真正的通讯能力呢?
相对而言,指的是docker0这个网桥,docker0实际上是一个假的网桥. 他只能让本机的容器间具有通讯的能力. 却不能让不同主机之间的容器进行通讯.
我们现在要配置一个,使用真正的物理网卡实现的网桥. 这个网桥能够跟外面的主机进行通讯.
创建网桥有多种方法. 可以通过工具创建,这里我们使用修改配置文件的方式创建网桥. 具体操作如下:
第一步: 进入到/etc/sysconfig/network-scripts/
第二步: 拷贝ifcfg-ens33
cp -a ifcfg-ens33 ifcfg-br0
TYPE="Ethernet" PROXY_METHOD=none BROWSER_ONLY=no #BOOTPROTO=dhcp BOOTPROTO=static DEFROUTE=yes IPV4_FAILURE_FATAL= IPV6INIT= IPV6_AUTOCONF= IPV6_DEFROUTE= IPV6_FAILURE_FATAL= IPV6_ADDR_GEN_MODE=stable-privacy NAME=ens33 UUID=1c73d826-0a58-4e97-8fd2-63ad33c4a5ad DEVICE= ONBOOT=" BRIDGE="br0" // 增加BRIDGE 删除下面几项 IPADDR=192.168.198.142 NETMASK=255.255.255.0 GATEWAY=192.168.198.2 BROADCAST=192.168.198.255 DNS1=192.168.198.2
DEVICE=br0 TYPE=Bridge ONBOOT=yes BOOTPROTO=static IPADDR=198.142 NETMASK=255.255.255.0 GATEWAY=198.2 BROADCAST=198.255 DNS1=198.2
第五步: 重启网络
systemctl network restart
第六步: 此时查看ip a
我们发现ens3的ip地址没有了,多了一个br0的网桥
默认情况下,docker并不能介入到br0去通讯
我们可以使用pipework来打通docker容器和br0网络
下面,设置pipework网络
1. 下载git yum install -y git
2. git clone https://github.com/jpetazzo/pipework 3. cp pipework/pipework /usr/local/bin/ chmod a+x /usr/local/bin/pipework
4. 启动容器,设置--net为none docker run --net=none --name tomcat -d tomcat9 这里--net必须设置成none,这样后面我们才能通过pipework给他设置一个独立的ip地址
5. 通过pipework赋予容器一个独立的ip地址 pipework 网桥类型 容器名称 ip地址 pipework br0 tomcat 198.145/24
6. 验证网络
首先,进入到容器,查看容器的网络
我们看到容器的网络确实设置为192.168.198.145
接下来, 接下来,我在本机mac上ping刚刚设置的192.168.198.145.是可以ping通的
然后在容器里,虚拟机里,本机macos上ping 192.168.198.145:8080都可以看到tomcat的启动页. 说明容器配置成功了
这时容器也有自己独立的ip了. 我们在另一台虚拟机上192.168.198.143上ping 192.168.198.145, 我们发现也是可以ping通的了.
而且也可以访问http://192.168.198.145:8080 并且能够看到tomcat的启动页
现在容器有了自己独立的ip,可以和各种主机/容器进行通讯了.