Docker 系统性入门+进阶实践-06Docker的网络
网络命名空间、端口映射、网络地址转换、路由等概念会在这一章讲解。
网络常用命令
- ip地址的查看
windows:ipconfig
linux:ip addr
- 网络连通性测试:
ping mayanan.cn
- 端口连通性测试
telnet mayanan.cn 80
- curl命令:请求web服务的
curl命令文档 - 路径探测跟踪
traceroot www.mayanan.cn
容器网络涉及到哪些问题?
- 容器为什么能获取到ip地址?
- 为什么宿主机可以ping通容器的ip?
- 为什么容器之间的ip是互通的?
- 为什么容器能ping通外网?
- 容器的端口转发是怎么回事?
容器间通信bridge模式
- 局域网之间电脑如何通信?
- 为什么同一台机器上的多个容器ip可以互通?
因为这些容器都默认连接到了linux bridge桥接网络docker0, docker0就帮助这些容器之间进行ip的通信
容器对外通信之bridge模式
- 安装查看linux bridge的命令
sudo apt-get install -y bridge-utils
- 查看当前系统的linux bridge列表
sudo brctl show
- 要想使容器能访问外网,容器所在的宿主机必须能访问外网
- linux查看网络中的路由命令
ip route
- iptable转发规则命令
sudo iptables --list -t nat
- 容器对外是如何通信的,主要就是借助于iptables,无论是容器与外网通信还是宿主机与外网通信,对于外网来说都是宿主机的公网ip在和他通信,
因为当容器和外网通信的时候需要进行网络地址转换,容器内的172.18.0.2需要通过linux bridge,例如默认的docker0,在通过docker0转到eth0,
然后eth0和外网进行通信。
网络知识补充NAT(network address translate)
- NAT一般用在路由器上面
NAT是用来解决IPv4地址不足的问题
NAT网络地址转换实际上就是从私有到公有,再从公有到私有的转换
NAT一般是由路由器来实现的。
创建和使用自定义bridge(上)
- 创建bridge
sudo docker network create --driver bridge mybridge
- 查看网络
sudo docker network ls
- 查看网络详情
sudo docker network inspect mybridge
- 创建一个容器使用刚刚创建的网络
sudo docker container run --rm -d --name box3 --network mybridge busybox /bin/sh -c "while true; do sleep 3600; done"
- 查看当前容器的详情,同时也能看到使用的network
sudo docker container inspect box3
- 再次查看我们的网络详情
sudo docker network inspect mybridge
发现该网段下已经有了一个容器,也就是刚刚创建的box容器 - 现在box3和上面创建的box1和box2没有在同一个网络,无法直接通信,可不可以让一个容器同时连接两个网络,答案是:可以的
为box3增加一个网络连接,连接到docker0这个网络接口也就是默认的bridge这个网络,
sudo docker network connect bridge box3
- 再次查看bridge这个网络详情
sudo docker network inspect bridge
发现该网段下多个一个容器,box3 - 再次查看box3容器的详情
sudo docker container inspect box3
发现box3的networks有两个网络连接了,一个是默认的bridge, 一个是我们自己创建的mybridge, - 此时在通过box3容器去ping容器box1或box2,ping成功了,因为box3已经属于bridge这个网段了
sudo docker container exec box3 ping 172.18.0.2
- 我们可以查看box3容器中的ip地址
sudo docker container exec box3 ip addr
我们发现,已经有两个id地址了:
- 将一个容器从一个网络中移除
sudo docker network disconnect bridge box3
创建和使用自定义bridge(下)
- 我们在创建一个容器,将该容器与box3在同一网段内
sudo docker container run --rm -d --name box4 --network mybridge busybox /bin/sh -c "while true; do sleep 3600; done"
因为box3和box4在同一个linux bridge下面的mybridge里,又因为mybridge是我们自己定义的,
所以box3和box4可以通过该容器名进行互相ping通
sudo docker container exec box4 ping box3
这样是可以ping通的,box1和box2虽然都在默认的bridge下面,因为不是自定义的,所以box1和box2不能通过容器名ping,只能通过对应的ip地址ping通。
- 总结:这说明了自定义的mybridge有dns的功能,可以帮我们把容器名解析为对应的ip地址;而默认的bridge不具有dns的功能。
- 创建network网络时,可以自定义bridge、gateway、subnet等
sudo docker network create --driver bridge --subnet 192.168.1.0/24 --gateway 192.168.1.1 demo
查看network详情
sudo docker network inspect demo
创建2个容器使用该网络
sudo docker container run --rm -d --name box5 --network demo busybox /bin/sh -c "while true; do sleep 3600; done"
sudo docker container run --rm -d --name box6 --network demo busybox /bin/sh -c "while true; do sleep 3600; done"
查看demo网络下的容器
sudo docker network inspect demo
容器的端口转发
- 容器内部访问外网的话,需要通过NAT网络地址转换,走默认的网络bridge或者自定义的网络mybridge
- 外网访问容器内部的话,需要通过端口映射/容器端口转发
- 启动nginx容器服务,进行端口映射
sudo docker container run --rm -it -p 8080:80 nginx
注意:8080是对外提供的端口,80是容器内部使用的端口 - 为什么通过-p就可以实现8080到80端口的转发?
实际上还是iptables在起作用
sudo iptables -t nat -nvxL
端口转发和Dockerfile
Dockerfile文件:
FROM python:3.9-slim
WORKDIR /usr/src/app
COPY app /usr/src/app
RUN bash run.sh
EXPOSE 5000
ENTRYPOINT ["flask", "run"]
CMD ["-h", "0.0.0.0"]
EXPOSE的作用就是告诉使用该镜像的用户,此端口是向外暴露的。
host网络详解
- 创建两个busybox容器,一个使用bridge网络,另一个使用host网络
sudo docker container run -d --rm --name box1 busybox /bin/sh -c "while true; do sleep 3600; done"
sudo docker container run -d --rm --name box2 --network host busybox /bin/sh -c "while true; do sleep 3600; done"
- 查看新建的两个容器的ip地址
sudo docker exec box1 ifconfig
sudo docker exec box2 ifconfig
所谓的host网络也就是说容器与我们的主机采用同一个网络,而bridge网络则是单独的网络
3. 我们创建一个none网络类型的容器
sudo docker container run --rm -d --name box1 --network none busybox /bin/sh -c "while true; do sleep 3600; done"
查看该容器的网络
sudo docker container exec box1 ip addr
我们发现它只有一个lo会还网卡,没有其它的网络,应用场景式,当我们使用容器编排工具的时候,
如果我们希望docker只为我们创建一个容器,我们自己为该容器配置网络时,none就用上了。
linux网络命名空间
- linux的Namespace(命名空间)技术是一种隔离技术,常用的Namespace有user namespace、process namespace、network namespace
在docker容器中,不同的容器通过network namespace进行了网络隔离,也就是不同的容器有各自的IP地址,路由表,互不影响 - 容器技术特别依赖于底层的linux技术,如:linux中namespace资源隔离、cgroup限制资源的消耗等
- 测试实验网络命名空间
创建bridge:
sudo brctl addbr mydocker0
sudo brctl show
准备一个shell脚本:
脚本名字:add-ns-to-br.sh
脚本内容:
#!/bin/bash
bridge=$1
namespace=$2
addr=$3
vethA=veth-$namespace
vethB=eth00
sudo ip netns add $namespace
sudo ip link add $vethA type veth peer name $vethB
sudo ip link set $vethB netns $namespace
sudo ip netns exec $namespace ip addr add $addr dev $vethB
sudo ip netns exec $namespace ip link set $vethB up
sudo ip link set $vethA up
sudo brctl addif $bridge $vethA
脚本执行:
sh add-ns-to-br.sh mydocker0 ns1 172.16.1.1/16
sh add-ns-to-br.sh mydocker0 ns2 172.16.1.2/16
把mydocker0这个bridge up起来:
sudo ip link set dev mydocker0 up
验证:
参考文档
- 当我们创建了一个docker container的时候,背后肯定是有一个网络命名空间的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)