Docker 容器网络
Docker 容器网络
网络只不过是一个区域【数据交流】
- 默认情况下,所有容器都运行在 Docker 默认的网络空间中。
- 在默认网络中,每个容器都可以与其他容器通信,我们可以创建网络隔离。
Docker 网络类型
一般情况,分三种:
- none:对于这个容器,禁用所有网络
- host:对于独立容器,直接使用宿主机的网络
- bridge:配置桥接网络,桥接网络使用软件桥接,允许连接到同一桥接网络的容器进行通信,同时提供与未连接到该桥接网络的容器的隔离。默认使用的网络模式【启动 Docker 时,会自动创建一个默认的桥接网络】
默认桥接网络的一个缺点是不支持使用 DNS 自动发现容器服务。因此,如果您希望属于默认网络的容器能够相互通信,则必须使用
--link
选项静态允许通信发生。此外,通信需要容器之间的端口转发。并采用的复杂配置模式:overlay, ipvlan, macvlan 三者分别覆盖网络、控制 IP、控制 MAC
开始测试前需要两个容器 container
- 容器 A:
docker run -dit --name c-a alpine ash
- 容器 B:
docker run -dit --name c-b alpine ash
-it 应该都知道,
-d
是挂后台的意思
- alpine 镜像是基于 Alpine Linux 的最小 Docker 镜像,一般进行测试使用
- ash 是 shell,属于 Bourne shell 简化版本,特点是占用系统资源最少,感兴趣可以去学习,不过主流是 bash, zsh
上面在创建时,并没有什么特别的,根据默认创建那么它们应该是使用相同给默认桥接网络
learn@debian10:~/work$ docker network ls NETWORK ID NAME DRIVER SCOPE c8e2262fa6ef bridge bridge local 5050dfe48c19 host host local ac4d3767e763 none null local
默认 bridge 网络的名称也是 bridge,追查 c8e2262fa6ef
网络,就是默认 bridge 那个使用 docker network inspect <network-name|network-id>
learn@debian10:~/work$ docker network inspect bridge [ { "Name": "bridge", "Id": "c8e2262fa6ef5bf351c325efe2bebf715c8174641ee3be711e2989aed13c8803", "Created": "2023-04-09T20:35:16.356724826+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": { "83358fcb0195b367b553d7bb610d09a0f64bdbf77afb4b55a2d2371e1b69c1e9": { "Name": "c-b", "EndpointID": "1e9a8d123a4b38af5119185318bc43214b64ea49c2edb197ec986f136ba44578", "MacAddress": "02:42:ac:11:00:03", "IPv4Address": "172.17.0.3/16", "IPv6Address": "" }, "9fe00453457a633a650d049083cc85c39b6b55a617e2d3b49d86864a1231d7e7": { "Name": "c-a", "EndpointID": "8a69f2d9e54411358b79138b3c662185c27d6d689d9ea26d289c49a0c9a4f9b9", "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": {} } ]
在 Containers
属性是可以看到它连接的两个容器 c-a
和 c-b
- 网络配置中可以看到网关是
172.17.0.1
c-a
分配的 IPv4 是172.17.0.2/16
c-b
分配的 IPv4 是172.17.0.3/16
我们使用 docker attach <container-name>
连接容器
- 说明这个子命令作用是将本地标准流附加到正在运行的容器
learn@debian10:~/work$ docker attach c-a / #
接下来我们使用的是 alpine 的 ash 作为 shell 不是 bash,我们已经进入 alpine 的 c-a 容器中
# 查看 c-a 中的网络接口,下面是完整命令,简化是 ip a # 为什么没有使用 ifconfig,已经快淘汰 ... ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000 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 4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever
- lo 是本地回环,学习过计算机网络应该都知道
- eth0@if5 接口是连接 bridge 网络的网卡,其中的
172.17.0.2/16
是否眼熟 😋 - 同样的方法可以在
c-b
中验证
注意网络接口和网卡说法是大致相同的
开始网络测试
- 网络连通性测试工具 ping
- 使用 -c 选项是设置测试次数,对于参数是正整数
# 测试公网 ping -c 4 baidu.com PING baidu.com (39.156.66.10): 56 data bytes 64 bytes from 39.156.66.10: seq=0 ttl=49 time=24.285 ms 64 bytes from 39.156.66.10: seq=1 ttl=49 time=31.348 ms 64 bytes from 39.156.66.10: seq=2 ttl=49 time=23.836 ms 64 bytes from 39.156.66.10: seq=3 ttl=49 time=22.960 ms --- baidu.com ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 22.960/25.607/31.348 ms # 测试 c-b 容器 ping -c 4 172.17.0.3 PING 172.17.0.3 (172.17.0.3): 56 data bytes 64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.217 ms 64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.305 ms 64 bytes from 172.17.0.3: seq=2 ttl=64 time=0.392 ms 64 bytes from 172.17.0.3: seq=3 ttl=64 time=0.227 ms --- 172.17.0.3 ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 0.217/0.285/0.392 ms
用同样方法测试另一个容器,可以发现它们是网络互通的,并且默认 bridge 并非封闭的
如果你需要删除容器 c-a, c-b
- docker container stop c-a c-b
- docker container rm c-a c-b
如果你是学习,下面命令可以一次性全部删除 停止的容器
- docker container prune
使用用户定义的桥接网络
创建一个我们自定义的 bridge 类型网络:test-net
- 语法大体:
docker network create --driver <net-type> <net-name>
--driver
选项设置网络类型,没有默认bridge
开始实验:
# 创建网络 test-net docker network create --driver bridge test-net 3477f402ce19f4f6d93eb2cd126040023151ec7fe50ddbd7ed8c824b75304b70 # 查看当前所有网络 docker network ls NETWORK ID NAME DRIVER SCOPE 85af1da27cc7 bridge bridge local 5050dfe48c19 host host local ac4d3767e763 none null local 3477f402ce19 test-net bridge local
通过 docker network inspect <net-name>
查看网络配置
learn@debian10:~/work$ docker network inspect test-net [ { "Name": "test-net", "Id": "3477f402ce19f4f6d93eb2cd126040023151ec7fe50ddbd7ed8c824b75304b70", "Created": "2023-04-10T18:40:36.149310552+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": {}, "Options": {}, "Labels": {} } ]
其网关与之前默认网络的有所不同 172.18.0.1
我们布置三个容器
# c1 和 c2 容器设置为 test-net 网络 docker run -dit --name c1 --network test-net alpine ash docker run -dit --name c2 --network test-net alpine ash # c3 使用默认 bridge docker run -dit --name c3 alpine ash
使用 docker network inspect <net-name>
检查 test-net 变化,像之前默认测试一样
learn@debian10:~/work$ docker network inspect test-net [ { "Name": "test-net", "Id": "3477f402ce19f4f6d93eb2cd126040023151ec7fe50ddbd7ed8c824b75304b70", "Created": "2023-04-10T18:40:36.149310552+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": { "0e02f61d92676b14a1fefdc500b52d239e63717463f8b7994ed00752c3b975d6": { "Name": "c1", "EndpointID": "33289017f78d0a8bfda7339958a1b118ed2cb7a9a1c1e4bb1a2c2b8ad5558d7b", "MacAddress": "02:42:ac:12:00:02", "IPv4Address": "172.18.0.2/16", "IPv6Address": "" }, "e4b657a0202f0d5bcc7b521c9c2b01910316b6dd8feb84bfad2667679fef457e": { "Name": "c2", "EndpointID": "b4c5b988276f73ea2aea06374191bd9ccb53bfe11fa22001680db062fe6c4d3c", "MacAddress": "02:42:ac:12:00:03", "IPv4Address": "172.18.0.3/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ]
知道它们的 IPv4
- c1: 172.18.0.2/16
- c2: 172.18.0.3/16
- c3: 172.17.0.2/16
之后分别进入其中进行测试
- c1 与 c2 连通
- c1 与 c3 阻塞
- c2 与 c3 阻塞
网络成功实现隔离,其实学习过计算机网络看 IP 地址分块也应该知道它们不在同一个网络中。
一个新手比较感兴趣的问题:使用代理
通过设置环境变量就可以实现,在构建镜像或创建容器时设置环境变量
HTTP_PROXY
或HTTPS_PROXY
就可以比如:你代理是
https://192.168.1.12:3128
使用docker run -dit alpine ash --env HTTPS_PROXY="https://192.168.1.12:3128"
就可以了
这只是 Docker 网络的一小部分,如果需要进一步深入 👉 https://docs.docker.com/network/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了