bridge 网络
bridge 网络,也称为单机桥接网络,是 Docker 默认的网络模式。该网络模式只能存在于单个 Docker 主机上,其只能用于连接所在 Docker 主机上的容器。
docker0 网桥
查看 docker0 网桥。
bridge 网络模式中具有一个默认的虚拟网桥 docker0,通过 ip addr 或 ifconfig 命令都可查看到。
通过 docker network inspect bridge 也可以查看到网络名称为 bridge 的网络的详情。
可以看到该网络的驱动为 bridge,其网桥名称为 docker0。只不过,目前该网络上还没有连接任何容器。
docker0 网桥工作原理
容器与网桥间是通过 veth pair 技术实现的连接,网桥与外网间是通过“网络地址转换 NAT 技术”实现的连接,即将通信的数据包中的内网地址转换为外网地址。
Bridge 驱动的底层是基于 Linux 内核的 Linux Bridge 技术。该技术已经经历了近 20 年的考验,这就意味着该模式是高性能且非常稳定的。
下面通过一个案例来熟悉docker中的bridge网络。案例docker中的网络结构如图:
一些指令
①docker network inspect xxx 查看当前 xxx 网络的整体连接情况。这里前面已经执行过了,不再截图说明。
②使用 brctl show 命令可以查看本机当前所有网桥及其连接情况。可以看到,当前宿主机中只有一个网桥 docker0,interfaces为0,表明网桥docker0上没有接口。
创建两个容器并指定网络
创建两个容器并指定网络,然后通过查看各个网络情况了解bridge网络。
docker run -d --name bb1 --network bridge busybox /bin/sh -c "while true; do sleep 3600; done"
docker run -d --name bb2 --network bridge busybox /bin/sh -c "while true; do sleep 3600; done"
查看 bridge 网络整体连接
现在通过 docker network inspect 命令查看当前 bridge 网络的整体连接情况。
在 Containers 中可以查看到当前名称为 bridge 的网络中连接的 bb1 与 bb2 两个容器。这两个容器及宿主机,其实就是三个完全独立的 Network Namespace。
查看宿主机和容器的接口
此时在宿主机上通过 ip a 命令查看当前主机的网络接口情况。
这两个 veth 就是由 Libnetwork 生成的 veth pair 中的宿主机中的 EndPoint。
在两个容器中分别使用 ip a 命令查看它们的地址情况,可以看到它们的接口正好与宿主机中的接口构成两对 pair。
查询网桥连接情况
可以看到其上连接着两 vethxxx 的接口,就是前面连接 bb1 与 bb2 上两个 eth0 的两个接口。
查看容器详情
通过 docker inspect 查看容器的详情(以bb1为例),可以看到,其网络连接中的网关 Geteway 的 IP 地址就是 docker0 网桥的地址。
[root@localhost ~]# docker inspect bb1
[
{
"Id": "cb521beacba589b5bfec4170b7ddb3219e3b8b2ae5c072c36ed77f1af6e54a52",
"Created": "2024-05-15T13:17:43.284110713Z",
"Path": "/bin/sh",
"Args": [
"-c",
"while true; do sleep 3600; done"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 6098,
"ExitCode": 0,
"Error": "",
"StartedAt": "2024-05-15T13:17:45.028717252Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a",
"ResolvConfPath": "/var/lib/docker/containers/cb521beacba589b5bfec4170b7ddb3219e3b8b2ae5c072c36ed77f1af6e54a52/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/cb521beacba589b5bfec4170b7ddb3219e3b8b2ae5c072c36ed77f1af6e54a52/hostname",
"HostsPath": "/var/lib/docker/containers/cb521beacba589b5bfec4170b7ddb3219e3b8b2ae5c072c36ed77f1af6e54a52/hosts",
"LogPath": "/var/lib/docker/containers/cb521beacba589b5bfec4170b7ddb3219e3b8b2ae5c072c36ed77f1af6e54a52/cb521beacba589b5bfec4170b7ddb3219e3b8b2ae5c072c36ed77f1af6e54a52-json.log",
"Name": "/bb1",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "bridge",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"ConsoleSize": [
40,
132
],
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": [],
"BlkioDeviceWriteBps": [],
"BlkioDeviceReadIOps": [],
"BlkioDeviceWriteIOps": [],
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": [],
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware",
"/sys/devices/virtual/powercap"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/ac8e99985d11fa6b457cb7fa9efce993d2111a1f6bccc4f815f33f13c1982e1f-init/diff:/var/lib/docker/overlay2/510f666ce3653dadef3414d0b2c9df7f5c9c5a574555247f240fa6a76100be74/diff",
"MergedDir": "/var/lib/docker/overlay2/ac8e99985d11fa6b457cb7fa9efce993d2111a1f6bccc4f815f33f13c1982e1f/merged",
"UpperDir": "/var/lib/docker/overlay2/ac8e99985d11fa6b457cb7fa9efce993d2111a1f6bccc4f815f33f13c1982e1f/diff",
"WorkDir": "/var/lib/docker/overlay2/ac8e99985d11fa6b457cb7fa9efce993d2111a1f6bccc4f815f33f13c1982e1f/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "cb521beacba5",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"while true; do sleep 3600; done"
],
"Image": "busybox",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "044389ce7180bd393cd2592c0b5d4b5ce7b33f9c5e110337f13240223482dddc",
"SandboxKey": "/var/run/docker/netns/044389ce7180",
"Ports": {},
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "2a43242cb128722926da76326c7478bc710fc43b4da2cd460df835894a48bed6",
"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,
"MacAddress": "02:42:ac:11:00:02",
"NetworkID": "6dc3704c6a60e42cb6a8218abdd6c9f05f95b2405d2cb2a7dbdf61797a149d8d",
"EndpointID": "2a43242cb128722926da76326c7478bc710fc43b4da2cd460df835894a48bed6",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DriverOpts": null,
"DNSNames": null
}
}
}
}
]
创建网络
通过 docker network create 命令可以创建指定名称与类型的网络。-d 选项用于指定要创建网络时所使用的驱动,即创建的网络类型。最后的 bridge2 则是新创建网络的名称。
创建完成后,查看宿主机支持的网络和宿主机网桥。如图:
创建第三个容器并指定网络
创建一个新的 BusyBox 容器 bb3,其连接在新建的 bridge2 网络上。
如果不指定,默认连接到默认的 bridge 网络。
docker run -d --name bb3 --network bridge2 busybox /bin/sh -c "while true; do sleep 3600; done"
查看新建网络详情
此时查看 bridge2 的网络详情,可以看到容器 bb3 已经连接到了上面。
查看宿主机网络接口
此时查看当前宿主机的网络接口情况,发现多出了两个接口。其中一个网桥接口br-xxx,一个连接 bb3 的接口 vethxxx@if57。
查看新增容器网络接口
此时查看容器 bb3 的网络接口,发现其 接口正好是宿主机对应接口的 pair 接口。
查看宿主机网桥
此时再查看网桥情况,发现新增网桥上增加了一个接口,而该接口正好就是宿主机上的 58号接口。并且,该接口的 IP 为 172.20.0.2/16(容器bb3) ,与 bridge 网络172.17.0.3/16(容器bb2) 不是同一网段,所以它们之间是不能相互通信的。
容器连接到指定网络
现在要将容器 bb2 连接到新建的 bridge2 网络上。可以使用 docker network connect 命令。
发现其同时具有两个网络接口,分别连接在两个不同的网络上。
容器互 ping
容器 bb2 与 bb3 互 ping 是可以 ping 通的。
但 bb3 要 ping 容器 bb2 的另一网段的 IP 是 ping 不通的。
容器互 ping 容器名
那么无论容器 IP 如何变化,都将不影响服务与容器的连接。
案例总结
通过上述容器间连接案例,相信已经对bridge网络有了更深刻的理解。