Docker 网络模式
- bridge
- host
- container模式
- none
- 用户自定义模式(bridge、overlay、macvlan)
Docker的网络模式大概可以分为5种类型。安装完 Docker,宿主机默认会创建三个网络,分别是bridge网络,host网络,none网络,可以使用docker network ls命令查看。
[root@tuling ~]$ docker network ls
NETWORK ID NAME DRIVER SCOPE
99fe18249fa6 bridge bridge local
e60bf8b6ed5b host host local
3a142d398cf9 none null local
bridge方式(默认)
容器的默认网络模式,docker在安装时会创建一个名为docker0的Linux bridge,在不指定--network的情况下,创建的容器都会默认挂到docker0上面。bridge模式为容器创建独立的网络栈,保证容器内的进程使用独立的网络环境,使容器之间,容器和docker host之间实现网络隔离。
Host IP为192.168.0.2, 容器网络为172.17.0.0/16 下边我们看下docker所提供的四种网络: 创建容器:(由于是默认设置,这里没指定网络--net="bridge"。另外可以看到容器内创建了eth0)
[root@localhost ~]$ docker run -i -t centos:centos7 /bin/bash
root@e2187aa35875:$ ip addr
1: lo: 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
75: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:2/64 scope link
valid_lft forever preferred_lft forever
容器与Host网络是连通的:
root@e2187aa35875:# ping 192.168.0.2
PING 192.168.0.2 (192.168.0.2): 48 data bytes
56 bytes from 192.168.0.2: icmp_seq=0 ttl=64 time=0.124 ms
# eth0实际上是veth pair的一端,另一端(vethb689485)连在docker0网桥上:
[root@localhost ~]$ ethtool -S vethb689485
NIC statistics:
peer_ifindex: 75
[root@localhost ~]$ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.56847afe9799 no vethb689485
原理
通过Iptables实现容器内访问外部网络:
[root@localhost ~]# iptables-save |grep 172.17.0.*
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A FORWARD -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 5000 -j ACCEPT
none方式
指定方法: --net="none" 可以看到,这样创建出来的容器完全没有网络:
[root@localhost ~]$ docker run -i -t --net="none" centos:centos7 /bin/bash
root@061364719a22:$ ip addr
1: lo: 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
root@061364719a22:$ ping 192.168.0.2
PING 192.168.0.2 (192.168.0.2): 48 data bytes
ping: sending packet: Network is unreachable
那这种方式,有什么用途呢? 这种方式将网络创建的责任完全交给用户。 可以实现更加灵活复杂的网络。 另外这种容器可以可以通过link容器实现通信。
host方式
指定方法:--net="host" 使用host模式的容器可以直接使用docker host的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。
container复用方式
指定方法: --net="container:name or id" 如下例子可以看出来,两者的网络完全相同。
[root@localhost ~]$ docker run -i -t centos:centos7 /bin/bash
root@02aac28b9234:$ ip addr
1: lo: 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
77: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:3/64 scope link
valid_lft forever preferred_lft forever
[root@localhost ~]$ docker run -i -t --net="container:02aac28b9234" centos:centos7 /bin/bash
root@02aac28b9234:$ ip addr
1: lo: 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
77: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:3/64 scope link
valid_lft forever preferred_lft forever
这样的好处是如果部署一个应用,可以将应用的不同组件部署在不同的容器中,对外可以看上出是一个整体
user-defined模式
用户自定义模式主要可选的有三种网络驱动:bridge、overlay、macvlan。bridge驱动用于创建类似于前面提到的bridge网络;overlay和macvlan驱动用于创建跨主机的网络、IP等。
跨主机网络会在后面高级课程讲到。
可以在启动容器之前在Docker中创建网络。这可以使用以下命令完成 语法:
docker network create --driver drivername name
选项:
- drivername - 这是用于网络驱动程序的名称。
- name - 这是给网络的名称。
这边用bridge举例:
[root@tuling ~]$ docker network create --driver bridge new_nw
c88bc38133ea9c8a9657d915294b4aa42525240096f40e607b4819ff5e1539ee
查看:
[root@tuling ~]$ docker network ls
NETWORK ID NAME DRIVER SCOPE
99fe18249fa6 bridge bridge local
e60bf8b6ed5b host host local
c88bc38133ea new_nw bridge local
3a142d398cf9 none null local
现在可以在启动容器时附加新网络。所以让我们使用以下命令启动ubuntu容器
sudo docker run -dit --network=new_nw ubuntu:latest /bin/bash
现在,如果我们通过以下命令检查网络名称,您现在将看到容器已连接到新的网桥。
[root@tuling ~]$ docker network inspect new_nw
[
{
"Name": "new_nw",
"Id": "c88bc38133ea9c8a9657d915294b4aa42525240096f40e607b4819ff5e1539ee",
"Created": "2020-02-27T11:25:09.921639153+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"93d3c6b0ab95e145346bb6ab47e3e85af5b6c01efce3036527e1681f568959a7": {
"Name": "stupefied_pare",
"EndpointID": "888a4cdcf0448e7216ee5ee4c5ded4a4c04e395f6f62fb112639a1ae61f9b0ec",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
发现一个容器已经链接到网桥。