目录
一 docker网络介绍
1、在Docker中,默认情况下容器与容器、容器与外部宿主机的网络是隔离开来的。当你安装Docker的时候,docker会创建一个桥接器docker0,通过它才让容器与容器之间、与宿主机之间通信。
ifconfig docker0
docker0 Link encap:Ethernet HWaddr 02:42:db:c4:96:d3
inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:dbff:fec4:96d3/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:648 (648.0 B)
Docker安装的时候默认会创建三个不同的网络。你可以通过docker network ls命令查看这些网络
docker network ls
NETWORK ID NAME DRIVER SCOPE
f65bddc829ad bridge bridge local
887f3f66f5dc host host local
7d7c2584672c none null local
二、docker网络模式
Docker在创建容器时有五种网络模式,bridge为默认不需要用–net去指定,其他模式需要在创建容器时使用–net去指定
docker容器的网络有五种模式:
1、bridge模式,--net=bridge(默认)
dokcer网络的默认设置,为容器创建独立的网络命名空间,容器具有独立的网卡等所有单独的网络栈,是最常用的使用方式。在docker run启动容器的时候,如果不加–net参数,就默认采用这种网络模式。安装完docker,系统会自动添加一个供docker使用的网桥docker0,我们创建一个新的容器时,容器通过DHCP获取一个与docker0同网段的IP地址,并默认连接到docker0网桥,以此实现容器与宿主机的网络互通。
2、host模式,--net=host
Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。。
3、none模式,--net=none
为容器创建独立网络命名空间,但不为它做任何网络配置,容器中只有lo,用户可以在此基础上,对容器网络做任意定制。这个模式下,dokcer不为容器进行任何网络配置。需要我们自己为容器添加网卡,配置IP。因此,若想使用pipework配置docker容器的ip地址,必须要在none模式下才可以。
4、其他容器模式(即container模式,join模式),--net=container:NAME_or_ID
与host模式类似,只是容器将与指定的容器共享网络命名空间。这个模式就是指定一个已有的容器,共享该容器的IP和端口。除了网络方面两个容器共享,其他的如文件系统,进程等还是隔离开的。
5、用户自定义
:
docker 1.9版本以后新增的特性,允许容器使用第三方的网络实现或者创建单独的bridge网络,提供网络隔离能力。
这些网络模式在相互网络通信方面的对比如下所示:
(南北向通信指容器与宿主机外界的访问机制,东西向流量指同一宿主机上,与其他容器相互访问的机制。)
1)host模式
由于容器和宿主机共享同一个网络命名空间,换言之,容器的IP地址即为宿主机的IP地址。所以容器可以和宿主机一样,使用宿主机的任意网卡,实现和外界的通信。其网络模型可以参照下图:
采用host模式的容器,可以直接使用宿主机的IP地址与外界进行通信,若宿主机具有公有IP,那么容器也拥有这个公有IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行NAT转换,而且由于容器通信时,不再需要通过linuxbridge等方式转发或数据包的拆封,性能上有很大优势。当然,这种模式有优势,也就有劣势,主要包括以下几个方面:
1)最明显的就是容器不再拥有隔离、独立的网络栈。容器会与宿主机竞争网络栈的使用,并且容器的崩溃就可能导致宿主机崩溃,在生产环境中,这种问题可能是不被允许的。
2)容器内部将不再拥有所有的端口资源,因为一些端口已经被宿主机服务、bridge模式的容器端口绑定等其他服务占用掉了。
2)bridge模式
bridge模式是docker默认的。在这种模式下,docker为容器创建独立的网络栈,保证容器内的进程使用独立的网络环境,实现容器之间、容器与宿主机之间的网络栈隔离。同时,通过宿主机上的docker0网桥,容器可以与宿主机乃至外界进行网络通信。其网络模型可以参考下图:
从上面的网络模型可以看出,容器从原理上是可以与宿主机乃至外界的其他机器通信的。同一宿主机上,容器之间都是连接掉docker0这个网桥上的,它可以作为虚拟交换机使容器可以相互通信。然而,由于宿主机的IP地址与容器veth pair的 IP地址均不在同一个网段,故仅仅依靠veth pair和namespace的技术,还不足以使宿主机以外的网络主动发现容器的存在。为了使外界可以方位容器中的进程,docker采用了端口绑定的方式,也就是通过iptables的NAT,将宿主机上的端口端口流量转发到容器内的端口上。举一个简单的例子,使用下面的命令创建容器,并将宿主机的3306端口绑定到容器的3306端口:
# docker run -tid --name db -p 3306:3306 MySQL
在宿主机上,可以通过iptables -t nat -L -n,查到一条DNAT规则:
# DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 to:172.17.0.5:3306
上面的172.17.0.5即为bridge模式下,创建的容器IP。
很明显,bridge模式的容器与外界通信时,必定会占用宿主机上的端口,从而与宿主机竞争端口资源,对宿主机端口的管理会是一个比较大的问题。同时,由于容器与外界通信是基于三层上iptables NAT,性能和效率上的损耗是可以预见的。
3)none模式
在这种模式下,容器有独立的网络栈,但不包含任何网络配置,只具有lo这个loopback网卡用于进程通信。也就是说,none模式为容器做了最少的网络设置,但是俗话说得好“少即是多”,在没有网络配置的情况下,通过第三方工具或者手工的方式,开发这任意定制容器的网络,提供了最高的灵活性。
4)其他容器(container)模式
其他网络模式是docker中一种较为特别的网络的模式。在这个模式下的容器,会使用其他容器的网络命名空间,其网络隔离性会处于bridge桥接模式与host模式之间。当容器共享其他容器的网络命名空间,则在这两个容器之间不存在网络隔离,而她们又与宿主机以及除此之外其他的容器存在网络隔离。其网络模型可以参考下图:
在这种模式下的容器可以通过localhost来同一网络命名空间下的其他容器,传输效率较高。而且这种模式还节约了一定数量的网络资源,但它并没有改变容器与外界通信的方式。在一些特殊的场景中非常有用,例如,kubernetes的pod,kubernetes为pod创建一个基础设施容器,同一pod下的其他容器都以其他容器模式共享这个基础设施容器的网络命名空间,相互之间以localhost访问,构成一个统一的整体。
5)用户定义网络模式
在用户定义网络模式下,开发者可以使用任何docker支持的第三方网络driver来定制容器的网络。并且,docker 1.9以上的版本默认自带了bridge和overlay两种类型的自定义网络driver。可以用于集成calico、weave、openvswitch等第三方厂商的网络实现。 除了docker自带的bridge driver,其他的几种driver都可以实现容器的跨主机通信。而基于bdrige driver的网络,docker会自动为其创建iptables规则,保证与其他网络之间、与docker0之间的网络隔离。 例如,使用下面的命令创建一个基于bridge driver的自定义网络:
# docker network create bri1
则docker会自动生成如下的iptables规则,保证不同网络上的容器无法互相通信。
# -A DOCKER-ISOLATION -i br-8dba6df70456 -o docker0 -j DROP
# -A DOCKER-ISOLATION -i docker0 -o br-8dba6df70456 -j DROP
除此之外,bridge driver的所有行为都和默认的bridge模式完全一致。而overlay及其他driver,则可以实现容器的跨主机通信。
三、docker network 命令用法列表
基本用法
[root@app01 ~]# docker network create --help
Usage: docker network create [OPTIONS] NETWORK
Create a network
Options:
--attachable Enable manual container attachment
--aux-address map Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])
--config-from string The network from which copying the configuration
--config-only Create a configuration only network
-d, --driver string Driver to manage the Network (default "bridge")
--gateway strings IPv4 or IPv6 Gateway for the master subnet
--ingress Create swarm routing-mesh network
--internal Restrict external access to the network
--ip-range strings Allocate container ip from a sub-range
--ipam-driver string IP Address Management Driver (default "default")
--ipam-opt map Set IPAM driver specific options (default map[])
--ipv6 Enable IPv6 networking
--label list Set metadata on a network
-o, --opt map Set driver specific options (default map[])
--scope string Control the network's scope
--subnet strings Subnet in CIDR format that represents a network segment
1、ls: 查看网络列表 示例:
docker network ls
2、create: 创建一个网络
# 基础用法
docker network create --driver=bridge --gateway=172.16.100.1 --subnet=172.16.100.0/24 mynet
# 创建网络时是可以添加一系列参数的:
# --driver:驱动程序类型,不指定任何选项的时候默认的–driver(网络模式)也是bridge(桥接)
# --gateway:主子网的IPV4和IPV6的网关,不指定自动生成
# --subnet:代表网段的CIDR格式的子网,不指定自动生成
# mynet:自定义网络名称
3、rm: 删除一个网络. 示例
docker network rm mynet
#如果网络中有容器连接需要加 -f 参数强制删除,建议不要这样执行,网络中若没有任何容器连接直接执行删除即可.
4、inspect: 查看一个网络的详情 示例:
docker network inspect mynet
5、prune: 删除所有未使用的网络. 示例:
docker network prune
ps: -f 强制删除,不提供任何确认情况下删除.
6、connect: 将一个容器加入到一个网络中. 示例:
docker network connect 网络名称 容器ID/容器名称
7、disconnect: 与 connect 刚好相反, 从网络中断开一个容器的链接. 示例:
docker network disconnect 网络名称 容器ID/容器名称
ps: -f 参数强制删除
8、默认情况下,来自连接到默认网桥网络的容器的流量 不会转发到外界。要启用转发,您需要更改两个设置。这些不是Docker命令,它们会影响Docker主机的内核。
配置Linux内核以允许IP转发。
#如果下面命令的值为0,说明禁止进行IP转发;如果是1,则说明IP转发功能已经打开。
cat /proc/sys/net/ipv4/ip_forward
#临时开启,(写入内存,在内存中开启)
echo "1" > /proc/sys/net/ipv4/ip_forward
#永久开启,(写入内核)
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p ----加载,使得配置文件立即生效,等同于sysctl -p /etc/sysctl.conf
将策略的iptables FORWARD策略从更改DROP为 ACCEPT
iptables -P FORWARD ACCEPT
四、docker运行容器指定网络模式
1、bridge模式,指定不指定都是一样
docker run --name nginx0 -p 8080:80 -d nginx
docker run --net=bridge --name nginx1 -p 8081:80 -d nginx
#查看bridge网络,可以看到容器nginx0和nginx1的ip
[root@app01 nginx]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "4cac0b7e0b1abe7157b0183e1c92c3ada2de897db344abdca89384f4580032ce",
"Created": "2023-04-09T23:38:32.185797849+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"1823067a3bd8b62023793287eba1377f0bd70300d05b273f6e05d411c08fca9b": {
"Name": "nginx1",
"EndpointID": "69354cde26d8a5a141c20437029c99ab328f2c76eb4d164d98ed146d90be57fa",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"58702d97fd30b2d10c20de6608fc7c9c82485c48bb337dd2fbfc5812180f3cf9": {
"Name": "nginx0",
"EndpointID": "4a212c9017ea1240c749041a57733d21b3f515393da716b6f94cc4fe03290e0d",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
2、host模式
docker run --net=host --name nginx2 -d nginx
#查看host网络,可以看到容器nginx2
ocker network inspect host
3、自定义网络
docker network create --driver=bridge --gateway=172.16.100.1 --subnet=172.16.100.0/24 mynet
docker run --net=mynet --name nginx3 -p 8083:80 -d nginx
#查看mynet网络,可以看到容器nginx3的ip
[root@app01 nginx]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "e371dce8354f9f321388822c1ef17ae1df77d27b9049f68c8f8ff27e9596c85e",
"Created": "2023-06-05T17:01:30.23531511+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.16.100.0/24",
"Gateway": "172.16.100.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"fe40f798e06f7cd26a10c304e7728c8e575fd7083eea4ae2e13526f76db6bcd9": {
"Name": "nginx3",
"EndpointID": "7d9dcbe57845c9765be471d0b4bad8046ca4a9b46f99058e29c907eecd26771c",
"MacAddress": "02:42:ac:10:64:02",
"IPv4Address": "172.16.100.2/24",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
五、docker-compose启动容器使用网络
1、docker-compose启动容器,容器没指定网络,则会创建 文件夹名_default
的bridge,卸载容器会自动删除该网络
version: '3'
services:
nginx:
container_name: nginx
image: nginx
restart: always
ports:
- 8080:80
[root@app01 nginx]# docker network ls
NETWORK ID NAME DRIVER SCOPE
4cac0b7e0b1a bridge bridge local
785169e3d639 host host local
857fb25690cf nginx_default bridge local
1a2aa722b6ce none null local
2、创建容器时,使用已经创建的网络
#首先创建mynet网络
docker network create --driver=bridge --gateway=172.16.100.1 --subnet=172.16.100.0/24 mynet
[root@app01 nginx]# docker network ls
NETWORK ID NAME DRIVER SCOPE
4cac0b7e0b1a bridge bridge local
785169e3d639 host host local
e371dce8354f mynet bridge local
1a2aa722b6ce none null local
#编写yaml,使用mynet网络
[root@app01 nginx]# cat docker-compose.yaml
version: '3'
services:
nginx:
container_name: nginx
image: nginx
restart: always
ports:
- 8080:80
networks:
default:
external:
name: mynet
[root@app01 nginx]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "e371dce8354f9f321388822c1ef17ae1df77d27b9049f68c8f8ff27e9596c85e",
"Created": "2023-06-05T17:01:30.23531511+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.16.100.0/24",
"Gateway": "172.16.100.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"66e767b31c951f0a1ba38917a544171ebcce77a475aced0b7628be1e872a50f9": {
"Name": "nginx",
"EndpointID": "e39925dff5c8622f5c39330080bb947ef96608f6cb1a112f3feb0b3f6b07af9d",
"MacAddress": "02:42:ac:10:64:02",
"IPv4Address": "172.16.100.2/24",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
#或者docker-compose.yaml这样写
version: '3'
services:
nginx:
container_name: nginx
image: nginx
restart: always
ports:
- 8080:80
networks:
- mynet
networks:
mynet:
external: true