docker network
Docker网络和虚拟机网络一样,有很多种模式。
当安装Docker以后,会自动创建三个网络。可以使用docker network ls命令列出这些网络
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
440aefe8afa3 bridge bridge local
aa8d6325580f host host local
3eb717ea6240 none null local
常见的网络类型有以下四种 :
bridge:桥接模式(默认),创建一个桥接网络,内部网卡自动获取IP地址,向外访问是经过NAT(网络地址转换)。
host:不会创建出自己的网卡,和宿主机共享网络命名空间。即没有自己的IP,而是使用宿主机的IP和端口。
none:不配置网络。需要时,进行自定义配置。
container:容器网络连通, 和另外一个容器共享网络空间。
macvlan: 直接连接到物理网络
overlay: 允许不同宿主机上的容器相互通信
使用 ip addr 查看系统网卡, 会多出一个网卡
$ ip addr
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:1d:9f:bd:cd brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
brctl show 查看网桥,系统已经创建一个网桥
$ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02421d9fbdcd no
docker0是一个网桥,可以把其他网卡加入,它工作在二层,可以理解是一个交换机。每加入一个网卡,交换机便多一个口。
当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口,两个接口相当于用网线直连。 这对接口其中一个在容器内;另一个被加入到docker0 网桥中,名称以 veth 开头。
容器和主机可以通信,容器之间在一个局域里,也可以相互通信。Docker 创建了在主机和所有容器之间一个虚拟二层交换网络。
-----docker0--
| | |
veth0 veth1 veth2
----|--------|------|-----------
| | |
eth0 eth0 eth0
创建容器并运行
docker run --name bjbook -p 8000:8000 -it --rm python:3 python -m http.server
查看网桥
brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02421d9fbdcd no vethd123cb3
发现网桥中增加了名称为 vethd123cb3 的网卡。
进入到容器里,查看其网卡信息
$ docker exec -it bjbook bash
$ cat /proc/net/dev
$ cat /proc/net/fib_trie
发现其网卡IP为172.17.0.2/16
网络模式
macvlan,
bridge模式
bridge模式,–net=bridge(默认)
这是docker网络的默认设置,为容器创建独立的网络名字空间,容器具有独立的网卡等所有单独的网络栈, 是最常用的使用方式。
在docker run启动容器的时候,如果不加–net参数,就默认采用这种网络模式。安装完docker,系统会自动添加一个 供docker使用的网桥docker0,我们创建一个新的容器时,容器通过DHCP获取一个与docker0同网段的IP地址, 并默认连接到docker0网桥,以此实现容器与宿主机的网络互通。
实际实现是创建veth网卡,veth网卡是一对连接在一起的网卡。然后把其中一个网卡加入网桥,另外一个放在容器中。 这样就可以将多个容器放在同一个网桥上。
在IP层是通过NAT来实现的,通过网络地址转换,可以访问容器内的网路服务。
查看网络信息:
$ docker network inspect bridge
[
{
"Name": "bridge",
"Id": "47b1606e07c37288c76ad42e2798ac60d836954bdd77b2167c10633b5ba7ad1a",
"Created": "2022-11-28T11:24:09.381326089+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": {},
"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": {}
}
]
启动容器
docker run -p 8000:8000 -it --rm python:3 python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/)
容器之间互通。
实际IPTABLEs配置
$ iptables-save |grep 8000
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8000 -j ACCEPT
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 8000 -j MASQUERADE
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8000 -j DNAT --to-destination 172.17.0.2:8000
端口映射
默认是端口映射模式,启动时设置端口映射,将本机的tcp 1234端口映射到docker容器的1234端口
docker run -p 1234:1234 -d --rm zhang:v1
查看端口映射,参数为容器ID
docker port f2d8da7cb853
也可以使用iptables-save 命令查看所有的netfilter配置。
也可以通过docker inspect f2d8da7cb853 命令来查看容器的详细信息,包含了IP和端口映射信息。
也可以通过docker exec -it f2d8da7cb853 /bin/bash 命令进入容器来查看容器IP
上面没有设置docker网络, 会加入默认的docker网络空间。下面我们创建自定义的容器网络。
docker network create -d bridge mynet1
运行两个容器,并加入到mynet1网络中
docker run -it --rm --name aa1 --network mynet1 busybox sh
docker run -it --rm --name aa2 --network mynet1 busybox sh
容器名分别为aa1和aa2, 在aa1内部执行ping aa2, 可以ping通。说明自定义的容器网络, 在容器内部可以相互以主机名ping通。
查看其dns配置,和默认网络不同,其nameserver是本地的服务器 127.0.0.11
/ # cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0
容器命名为zhang1
docker run -p 9999:8000 -d –rm –name zhang1 zhang:v1
host模式
host模式,–net=host 和 –network host作用相同。
这个模式下创建出来的容器,直接使用容器宿主机的网络名字空间,例如网卡和IP都是和宿主机共用。 但容器的其他方面,如文件系统和进程等是和宿主机隔离的。
容器将不拥有自己独立的Network Namespace,即没有独立的网络环境。它和宿主机共用网卡和IP。 例如启动nginx服务,默认绑定在主机的80端口,不用创建端口映射。
$ docker run --rm -d --network host --name my_nginx nginx
1f378ca055340e87b3072e8cb15390c9b45a2b47ce4ebc8ec6dcfdec3e0503d5
查看运行的docker
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1f378ca05534 nginx "/docker-entrypoint.…" 36 seconds ago Up 35 seconds my_nginx
host模式优势是网络性能比较好,因为没有进行NAT。
劣势是网络隔离性不好,容器和宿主机的端口存在抢占行为。
host模式运行的docker 可以理解为一个进程, 可以直接使用宿主机的IP和端口,因此也不需要设置端口映射。
container模式
指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。
新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。 这样两个容器除了网络,其他的如文件系统和进程等是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
应用举例:
todo:
优势:节约的网络资源,多个容器共享网络空间。容器可以通过访问 localhost:port 来访问相同网络名字空间下的其他容器。
none模式
该模式Docker容器拥有自己的Network Namespace,但Docker容器没有任何网络配置。
这个Docker容器没有网卡、IP地址等信息。按需另外为Docker容器添加网卡、配置IP等。
none模式可以在容器创建时通过–network=none来指定。或使用 –net=none 指定。
应用举例:
例如一些计算任务,写入磁盘,不需要网络的情况下使用。
todo
创建桥接网络
创建一个桥接网络
$ docker network create --driver bridge my_bridge
查看已将创建了my_bridge
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
47b1606e07c3 bridge bridge local
aa8d6325580f host host local
4dc1bb25fc47 my_bridge bridge local
3eb717ea6240 none null local
查看多了一个网卡, 其IP地址为172.18.0.1
ifconfig
br-4dc1bb25fc47: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255
ether 02:42:cb:00:7a:7b 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