docker实战(三):docker网络模式(超详细)
亲们。来了别客气,尽量点赞,留关注,留住初心,取得潇洒..............................................
Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
1)优点
简化程序:
Docker 让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,便可以实现虚拟化。Docker改变了虚拟化的方式,使开发者可以直接将自己的成果放入Docker中进行管理。方便快捷已经是 Docker的最大优势,过去需要用数天乃至数周的任务,在Docker容器的处理下,只需要数秒就能完成。
避免选择恐惧症:
如果你有选择恐惧症,还是资深患者。那么你可以使用 Docker 打包你的纠结!比如 Docker 镜像;Docker 镜像中包含了运行环境和配置,所以 Docker 可以简化部署多种应用实例工作。比如 Web 应用、后台应用、数据库应用、大数据应用比如 Hadoop 集群、消息队列等等都可以打包成一个镜像部署。
节省开支:
一方面,云计算时代到来,使开发者不必为了追求效果而配置高额的硬件,Docker 改变了高性能必然高价格的思维定势。Docker 与云的结合,让云空间得到更充分的利用。不仅解决了硬件管理的问题,也改变了虚拟化的方式。
2)应用场景
Web 应用的自动化打包和发布。
自动化测试和持续集成、发布。
在服务型环境中部署和调整数据库或其他的后台应用。
从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境
================================================================================
docker网络序:
什么是Docker网络?
当你开始大规模使用Docker时,你会发现需要了解很多关于网络的知识
Docker作为目前最火的轻量级容器技术,有很多令人称道的功能,如Docker的镜像管理
然而,Docker同样有着很多不完善的地方,网络方面就是Docker比较薄弱的部分
因此,我们有必要深入了解Docker的网络知识,以满足更高的网络需求
安装Docker时,它会自动创建三个网络,bridge(创建容器默认连接到此网络)、 none 、host
默认网络
当你安装Docker时,它会自动创建三个网络。你可以使用以下docker network ls命令列出这些网络
[[email protected] ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
bb0db7cc0b6a bridge bridge local
3b8ad0e55908 host host local
1df39d09fe3d none null local
none 网络
- 故名思议,none 网络就是什么都没有的网络。
- 挂在这个网络下的容器除了 lo,没有其他任何网卡。
- 容器创建时,可以通过
--network=none
指定使用 none 网络。 - 一些对安全性要求高并且不需要联网的应用可以使用 none 网络
host 网络
- 连接到 host 网络的容器共享 Docker host 的网络栈,容器的网络配置与 host 完全一样。
- 可以通过 --network=host 指定使用 host 网络。
- 直接使用 Docker host 的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择 host 网络。
- 当然不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host 上已经使用的端口就不能再用了。
- Docker host 的另一个用途是让容器可以直接配置 host 网路。
- 比如某些跨 host 的网络解决方案,其本身也是以容器方式运行的,这些方案需要对网络进行配置
bridge网络
- Docker 安装时会创建一个 命名为 docker0 的 linux bridge。
- 如果不指定–network,创建的容器默认都会挂到 docker0 上。
- 可以通过docker network inspect bridge命令查看bridge 网络的配置信息:
[[email protected] ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
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: eno16777728: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:78:21:c4 brd ff:ff:ff:ff:ff:ff
inet 192.168.227.132/24 brd 192.168.227.255 scope global dynamic eno16777728
valid_lft 1014sec preferred_lft 1014sec
inet6 fe80::20c:29ff:fe78:21c4/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:4e:9b:b8:52 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:4eff:fe9b:b852/64 scope link
valid_lft forever preferred_lft forever
15: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 72:29:cc:56:ce:37 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::7029:ccff:fe56:ce37/64 scope link
valid_lft forever preferred_lft forever
Docker内置这三个网络,运行容器时,你可以使用该–network标志来指定容器应连接到哪些网络
该bridge网络代表docker0所有Docker安装中存在的网络
除非你使用该docker run --network=选项指定,否则Docker守护程序默认将容器连接到此网络
我们在使用docker run创建Docker容器时,可以用 --net 选项指定容器的网络模式,Docker可以有以下4种网络模式
host模式:使用 --net=host 指定。
none模式:使用 --net=none 指定。
bridge模式:使用 --net=bridge 指定,默认设置。
container模式:使用 --net=container:NAME_or_ID 指定
下面分别介绍一下Docker的各个网络模式。
Host模式
192.168.227.132
相当于Vmware中的桥接模式,与宿主机在同一个网络中,但没有独立IP地址
众所周知,Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程
Mount Namespace隔离文件系统,Network Namespace隔离网络等
一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离
一个Docker容器一般会分配一个独立的Network Namespace
但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace
而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
例如,我们在/24的机器上用host模式启动一个centos容器
[[email protected] ~]# docker run -it --network host --name=host-centos-test centos
[[email protected] /]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
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: eno16777728: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:78:21:c4 brd ff:ff:ff:ff:ff:ff
inet 192.168.227.132/24 brd 192.168.227.255 scope global dynamic eno16777728
valid_lft 1352sec preferred_lft 1352sec
inet6 fe80::20c:29ff:fe78:21c4/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:4e:9b:b8:52 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:4eff:fe9b:b852/64 scope link
valid_lft forever preferred_lft forever
15: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 72:29:cc:56:ce:37 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::7029:ccff:fe56:ce37/64 scope link
valid_lft forever preferred_lft forever该信息显示与未指定网络类型的创建时的一样
[[email protected] ~]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c09319c2ac8 centos "/bin/bash" 18 minutes ago Exited (1) 10 minutes ago host-centos-test
161108f3c46f nginx:1.15 "/bin/bash" 3 hours ago Exited (0) 3 hours ago hungry_bohr
5c7b37d5c51f centos "/bin/bash" 18 hours ago Exited (0) 10 minutes ago my-test
[[email protected] ~]# docker start host-centos-test
host-centos-test
[[email protected] ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c09319c2ac8 centos "/bin/bash" 19 minutes ago Up 9 seconds host-centos-test
[[email protected] ~]# ifconfig docker0
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
ether 02:42:c3:3d:ba:2d 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
[[email protected] ~]# docker start my-test
[[email protected] ~]# docker exec -it host-centos-test /bin/bash
[[email protected] /]# ifconfig
bash: ifconfig: command not found
[[email protected] /]# yum install -y net-tools
Failed to set locale, defaulting to C.UTF-8
Last metadata expiration check: 0:04:15 ago on Sun Apr 26 05:52:36 2020.
Dependencies resolved.
[[email protected] /]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
inet6 fe80::42:c3ff:fe3d:ba2d prefixlen 64 scopeid 0x20<link>
.....................
===================================================================================
可以看到,容器的网络使用的是宿主机的网络,但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
Container模式
在理解了host模式后,这个模式也就好理解了
这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享
新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等
同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信
None模式
该模式将容器放置在它自己的网络栈中,但是并不进行任何配置
实际上,该模式关闭了容器的网络功能,在以下两种情况下是有用的:容器并不需要网络(例如只需要写磁盘卷的批处理任务)
overlay
在docker1.7代码进行了重构,单独把网络部分独立出来编写,所以在docker1.8新加入的一个overlay网络模式。
Docker对于网络访问的控制也是在逐渐完善的。
Bridge模式
相当于Vmware中的Nat模式,容器使用独立network Namespace,并连接到docker0虚拟网卡(默认模式)
通过docker0网桥以及Iptables nat表配置与宿主机通信;bridge模式是Docker默认的网络设置
此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的Docker容器连接到一个虚拟网桥上
下面着重介绍一下此模式
(1)Bridge模式的拓扑
当Docker server启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。
虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
接下来就要为容器分配IP了,Docker会从RFC1918所定义的私有IP网段中,选择一个和宿主机不同的IP地址和子网分配给docker0,
连接到docker0的容器就从这个子网中选择一个未占用的IP使用。
如一般Docker会使用172.17.0.0/16这个网段,并将172.17.0.1/16分配给docker0网桥
(在主机上使用ifconfig命令是可以看到docker0的,可以认为它是网桥的管理接口,在宿主机上作为一块虚拟网卡使用)。
单机环境下的网络拓扑如下,主机地址为192.168.227.132/24
。
(2)Docker:网络模式详解
Docker完成以上网络配置的过程大致是这样的:
1)在主机上创建一对虚拟网卡veth pair设备。
veth设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。
因此,veth设备常用来连接两个网络设备。
2)Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0。
另一端放在主机中,以veth65f9这样类似的名字命名,并将这个网络设备加入到docker0网桥中,可以通过brctl show命令查看。
[[email protected] ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/nginx latest 602e111c06b6 2 days ago 127 MB
docker.io/centos latest 470671670cac 3 months ago 237 MB
docker.io/nginx 1.15 53f3fd8007f7 11 months ago 109 MB
[[email protected] ~]# docker run --name=ngixn-bridge --network bridge -p 8080:80 -d nginx:1.15
076e93ed0209c73abeba65c372f63d2961cc7f0c2959772c48d166baeeff8e53
[[email protected] ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/nginx latest 602e111c06b6 2 days ago 127 MB
docker.io/centos latest 470671670cac 3 months ago 237 MB
docker.io/nginx 1.15 53f3fd8007f7 11 months ago 109 MB
[[email protected] ~]# docker run --name=ngixn-bridge --network bridge -p 8080:80 -d nginx:1.15
076e93ed0209c73abeba65c372f63d2961cc7f0c2959772c48d166baeeff8e53
[[email protected] ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
076e93ed0209 nginx:1.15 "nginx -g 'daemon ..." About a minute ago Up About a minute 0.0.0.0:8080->80/tcp ngixn-bridge
5c7b37d5c51f centos "/bin/bash" 20 hours ago Up 4 minutes my-test
[[email protected] ~]# docker inspect 076e93ed0209
网络拓扑介绍完后,接着介绍一下bridge模式下容器是如何通信的
(3)bridge模式下容器的通信
在bridge模式下,连在同一网桥上的容器可以相互通信(若出于安全考虑,也可以禁止它们之间通信,
方法是在DOCKER_OPTS变量中设置–icc=false,这样只有使用–link才能使两个容器通信)。
Docker可以开启容器间通信(意味着默认配置–icc=true),也就是说,宿主机上的所有容器可以不受任何限制地相互通信,
这可能导致拒绝服务攻击。进一步地,Docker可以通过–ip_forward和–iptables两个选项控制容器间、容器和外部世界的通信。
容器也可以与外部通信,我们看一下主机上的Iptable规则,可以看到这么一条:
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
这条规则会将源地址为172.17.0.0/16的包(也就是从Docker容器产生的包),并且不是从docker0网卡发出的,
进行源地址转换,转换成主机网卡的地址。这么说可能不太好理解,举一个例子说明一下。
假设主机有一块网卡为eth0,IP地址为192.168.227.132/24,网关为192.168.227.2。
从主机上一个IP为172.17.0.1/16的容器中ping百度(180.76.3.151)。
IP包首先从容器发往自己的默认网关docker0,包到达docker0后,也就到达了主机上。
然后会查询主机的路由表,发现包应该从主机的eth0发往主机的网关192.168.227.132/24。
接着包会转发给eth0,并从eth0发出去(主机的ip_forward转发应该已经打开)。
这时候,上面的Iptable规则就会起作用,对包做SNAT转换,将源地址换为eth0的地址。
这样,在外界看来,这个包就是从192.168.227.132发出来的,Docker容器对外是不可见的。
那么,外面的机器是如何访问Docker容器的服务呢?
我们首先用下面命令创建一个含有web应用的容器,将容器的80端口映射到主机的80端口。
docker run --name=nginx_bridge --net=bridge -p 80:80 -d nginx:1.15
然后查看Iptable规则的变化,发现多了这样一条规则:
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80
此条规则就是对主机eth0收到的目的端口为80的tcp流量进行DNAT转换,将流量发往172.17.0.2:80,也就是我们上面创建的Docker容器。所以,外界只需访问192.168.227.132:80就可以访问到容器中的服务。
除此之外,我们还可以自定义Docker使用的IP地址、DNS等信息,甚至使用自己定义的网桥,但是其工作方式还是一样的。
http://192.168.227.132:8080/ 访问nginx:1.15容器
自定义网络
建议使用自定义的网桥来控制哪些容器可以相互通信,还可以自动DNS解析容器名称到IP地址。
Docker提供了创建这些网络的默认网络驱动程序,你可以创建一个新的Bridge网络,Overlay或Macvlan网络。
你还可以创建一个网络插件或远程网络进行完整的自定义和控制。
你可以根据需要创建任意数量的网络,并且可以在任何给定时间将容器连接到这些网络中的零个或多个网络。
此外,您可以连接并断开网络中的运行容器,而无需重新启动容器。
当容器连接到多个网络时,其外部连接通过第一个非内部网络以词法顺序提供。
接下来介绍Docker的内置网络驱动程序。
bridge
一个bridge网络是Docker中最常用的网络类型。
桥接网络类似于默认bridge网络,但添加一些新功能并删除一些旧的能力。
以下示例创建一些桥接网络,并对这些网络上的容器执行一些实验。
docker network create --driver bridge new-bridge (正常情况下应该开到下图)
但是在执行这个命令报错:
[[email protected] ~]# docker network create --driver bridge new-bridge
Error response from daemon: Failed to Setup IP tables: Unable to enable SKIP DNAT rule: (iptables failed: iptables --wait -t nat -I DOCKER -i br-373c2a402b29 -j RETURN: iptables: No chain/target/match by that name.
(exit status 1))
解决方案:
原因是关闭防火墙之后docker需要重启,执行以下命令重启docker即可:systemctl restart docker
[[email protected] ~]# docker network create --driver bridge new-bridge 这次正常
系统执行systemctl status firewalld 错误如下
解决方案:
[[email protected] ~]# systemctl start firewalld
[[email protected] ~]# firewall-cmd --permanent --zone=trusted --change-interface=docker0
success
[[email protected] ~]# firewall-cmd --reload
success
[[email protected] ~]# systemctl status firewalld
完美解决
查看为网桥(new-bridge)分配的ip
可以通过docker network inspect
new-bridge命令查看bridge 网络的配置信息:
[[email protected] ~]# docker network inspect new-bridge
[
{
"Name": "new-bridge", ---网桥名称
"Id": "1665806ba09867bba2eece91603015d1be34b769b009aeeb4bd6cc1fe0420c7c",
"Created": "2020-04-26T16:12:18.211700817+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16", --docker容器自动分配的Ip
"Gateway": "172.18.0.1" ---docker容器自动映射的网关
}
]
},
"Internal": false,
"Attachable": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]