文章目录
一、简述
Docker支持4种网络模式,如下所示:
1、host模式:使用 --network = host 参数;
2、container模式:使用 --network = container:NAME_or_ID 参数;
3、none模式:使用 --network = none 参数;
4、bridge模式:使用 --network = bridge 参数。缺省情况下,使用bridge模式(即,使用docker run启动一个容器时,若不指定 --network 参数,则默认使用bridge模式)。
二、host模式
在host模式下,容器和宿主机共用一个网络命名空间(Network Namespace),容器共享宿主机的网卡、IP和端口等资源。容器内的服务可以直接使用宿主机的端口,也可以直接使用宿主机的 IP 进行通信,不存在虚拟化网络带来的开销,性能上有很大的提升。但是,host模式也降低了容器与容器之间、容器与宿主机之间网络的隔离性,会引起网络资源的竞争和冲突。
缺点:隔离性差,不安全,会占用宿主机的端口。
优点:无需配置网络策略,只要能访问到宿主机,就能访问到容器。外部主机可以通过“宿主机IP:容器端口”访问容器,不用通过参数“-p 宿主机端口:容器端口”进行端口映射。
三、none模式
在none模式下,Docker容器拥有自己的网络命名空间(Network Namespace),但不会进行任何网络配置。即,none模式的Docker容器没有网卡、IP、路由等信息,需要我们自己为Docker容器添加网卡、配置IP等操作。
四、container模式
在container模式下,一个Docker容器会共享其他Docker容器的网络命名空间(Network Namespace),在这两个Docker容器之间不存在网络隔离。同时,这两个Docker容器又与宿主机、其他Docker容器存在网络隔离。
共享网络命名空间的这两个容器之间可以相互通信。虽然是两个容器,但可以理解为在同一容器里面,可以用localhost访问。这两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
K8S为Pod创建一个基础设施容器,同一Pod下的容器都以container模式共享这个基础设施容器的网络命名空间,相互之间以localhost访问,构成一个统一的整体。
五、bridge模式
缺省情况下,Docker容器就是bridge模式。
在bridge模式下,Docker容器没有对外IP(只有内部IP,172.17.0.x网段)。宿主机以外的世界不能直接通过容器IP和容器进行通信,只有宿主机可以直接通过容器IP和容器进行通信。但Docker容器通过宿主机的NAT规则后可以访问外网。
外部主机可以通过“宿主机IP:宿主机端口”访问容器,但是必须通过“-p 宿主机端口:容器端口”进行端口映射。
##运行MySQL容器
[root@localhost ~]# docker run --name container1 -p 3306:3306 \
-e MYSQL_ROOT_HOST=% -e MYSQL_ROOT_PASSWORD=123456 \
-v /etc/localtime:/etc/localtime \
-v /data/docker/mysql/conf/:/etc/mysql/conf.d \
-v /data/docker/mysql/logs:/var/log \
-v /data/docker/mysql/data:/var/lib/mysql --restart=always \
-d mysql:5.7
## 用docker inspect命令查看容器内部情况
[root@localhost ~]# docker inspect container1
......
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "f002912c521c5ca3bc3f......",
"EndpointID": "24ba5637c0b9795e868......",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
......
可以看到默认情况下(未设置--network参数)container1是bridge模式,它的IP是172.17.0.2,它的网关是172.17.0.1。
## 将容器container1删除
[root@localhost ~]# docker rm -f container1
## 删除后,docker run重新启动一个container2
[root@localhost ~]# docker run --name container2 -p 3306:3306 \
-e MYSQL_ROOT_HOST=% -e MYSQL_ROOT_PASSWORD=123456 \
-v /etc/localtime:/etc/localtime \
-v /data/docker/mysql/conf/:/etc/mysql/conf.d \
-v /data/docker/mysql/logs:/var/log \
-v /data/docker/mysql/data:/var/lib/mysql --restart=always \
-d mysql:5.7
## 用docker inspect命令查看容器内部情况
[root@localhost ~]# docker inspect container2
......
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "35837a848219fd42bfb6......",
"EndpointID": "33e4998ffb417ff29ef......",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
......
可见,container1被删除后,它之前所使用的IP地址被释放,然后被分配给了之后的container2。所以,随着一个Docker容器的启/停/增/删等操作,该容器的IP也可能会动态变化的。必须对Docker容器进行规划,不能通过IP地址来查找某个Docker容器。
Docker进程默认在宿主机上创建一个名叫 docker0 的网桥(其上有一个 docker0 内部接口),它在内核层连通了物理网卡和虚拟网卡,这就将所有Docker容器和宿主机都放到同一个网络。Docker默认指定了 docker0 接口 的 IP 地址和子网掩码,让宿主机和容器之间可以通过 docker0 网桥相互通信。凡是连接在 docker0 网桥上的Docker容器,就可以通过它来进行通信。
可以看一眼默认的网桥名:
[root@localhost ~]# docker network inspect bridge | grep name
"com.docker.network.bridge.name": "docker0",
可以看到默认的网桥名字就叫docker0
Docker进程启动一个Docker容器时,会根据docker0网桥的网段分配给Docker容器一个IP地址,称为容器IP。同时,docker0网桥是每个Docker容器的默认网关。因为在同一宿主机内的Docker容器都接入同一个docker0网桥,这样Docker容器之间就能够通过容器IP直接通信。
docker run 的时候,没有指定 --network 参数的话,默认使用bridge模式,使用的就是docker0网桥。在Linux宿主机执行 ip addr 命令,就可以看到 docker0 和自己create的Docker 子网(六、自建子网部分讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址
网桥docker0创建一对 对等的虚拟设备接口,一个叫veth,另一个叫eth0,成对匹配。整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth。在宿主机和容器内分别创建一个虚拟接口,并让他们彼此连通(这样一对接口叫veth pair)。
1)每个Docker容器内部也有一块网卡,网卡接口叫eth0;
2)docker0上面的每个veth匹配某个Docker容器内部的eth0,两两配对,一一匹配。
通过上述,将宿主机上的所有Docker容器都连接到这个内部网络上。两个Docker容器在同一个网络下,会从这个网桥docker0下各自拿到分配的IP,此时两个容器的网络就互通了。
如上图,docker0 网桥相当于一个交换机,它用于把宿主机的物理网卡和上面的Docker容器的虚拟网卡进行连接,让其可以进行联网通信。而docker0的IP地址就是Docker容器的网关。上图中红框所标出的就类似于进行连接的RJ45水晶头。eth0就相当于是Docker容器中虚拟出的网卡接口,veth相当于交换机上的接口。
六、自建子网
在宿主机上通过“docker network create --subnet 子网IP/掩码 子网名”创建子网,然后docker run时,使用“--network 子网名 --ip 所属子网的IP”。
只有宿主机可以通过“容器IP:容器端口”访问容器,外部主机不能访问容器。
示例:
## 创建子网
docker network create --subnet 192.168.100.0/24 --gateway=192.168.100.1 my-net
## 使用创建的子网来运行容器
docker run -d \
-p 8111:8111 \
-p 8112:8112 \
--name my-nginx \
--restart=always \
-v /etc/localtime:/etc/localtime \
-v ~/data/docker/nginx/static:/etc/nginx/html \
-v ~/data/docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-v ~/data/docker/nginx/log:/var/log/nginx \
-v ~/data/docker/nginx/conf.d:/etc/nginx/conf.d \
--network my-net --ip 192.168.100.2 \
nginx:1.18.0