Docker-Bridge Network 02 容器与外部通信

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介:

Docker-Bridge Network 02 容器与外部通信

本小节介绍bridge network模式下,容器与外部的通信。

1.前言2.容器访问外部2.1 访问外网2.2 原理2.3 一张图总结2.4 抓包3.外部访问容器3.1 创建nginx容器并从外部访问3.2 原理3.3 一张图总结3.4 抓包3.5 docker-proxy4.小结

1.前言
上一节介绍了容器之间的通信过程。容器中部署了服务,我们肯定要从外部去访问这个服务,那么,容器如何与外部进行通信呢?

2.容器访问外部
这一节,我们仍然使用bbox1容器进行实验。首先要确保虚拟机Host1能访问外网。在“准备Docker环境”那一节,介绍了虚拟机如何直接ping通百度。
要说明一点,外部网络不一定指互联网,外部与内部是相对的概念。只要是容器网络以外的网络,都可以称作外部网络,比如Host1所在的网络。

2.1 访问外网
[root@docker1 ~]# docker exec -it bbox1 sh
/ # ping www.baidu.com
PING www.baidu.com (180.101.49.11): 56 data bytes
64 bytes from 180.101.49.11: seq=0 ttl=51 time=21.308 ms
64 bytes from 180.101.49.11: seq=1 ttl=51 time=24.613 ms
2.2 原理
回顾一下当前容器的网络连接情况:

我们试着分析一下,bbox1发出ping包,根据bbox1的路由表,报文被送到了docker0。那docker0和enp0s3是怎么连接的呢?
Linux本身就有路由转发功能,所以其实linux系统本身可以作为一个路由器。执行命令cat /proc/sys/net/ipv4/ip_forward,能看到ip_forward=1,说明系统开启了路由转发。
那么docker0发出数据包后,应该是根据Host的路由表进行转发。而Host的默认路由是指向enp0s3的,所以enp0s3收到了数据包。
我个人理解,此时enp0s3上数据包的源IP是bbox1的,目的IP是baidu,应该是能够到达baidu的;但是在baidu发回应答包的时候,它不知道这个私网IP在哪,通过任何一级路由都找不到,所以enp0s3这里发出报文前就得进行SNAT。
具体回包过程我不太明白,有明白的同学麻烦具体解释一下,感谢。
说到SNAT,就必须得提到Linux内核的大杀器——IPtables了。
在虚拟机中执行iptables -t nat -vnL,查看nat表。

Chain POSTROUTING (policy ACCEPT 21 packets, 1479 bytes)
 pkts bytes target     prot opt in   out      source            destination         
    3   202 MASQUERADE  all  --  *   !docker0  172.17.0.0/16     0.0.0.0/0 
docker0发出报文后会经过linux内核的路由转发,到达enp0s3。而到达enp0s3之前,会经过iptables的POSTROUTING链进行SNAT,就是上面这条规则。大意是指把源IP为172.17.0.0/16、目的IP任意的报文,进行MASQUERADE(伪装),也就是SNAT,即把源IP和MAC替换,替换成路由选择之后的enp0s3的IP和MAC。

2.3 一张图总结

bbox1 ping 百度,报文发往docker0;
docker0发出报文,经过内核的路由转发和SNAT处理,将报文的源IP及MAC换成了enp0s3的IP和MAC,到达enp0s3;
enp0s3发出报文,访问百度。
2.4 抓包
当前网络设备及地址如下:

设备 IP MAC
容器bbox1 172.17.0.2 02:42:ac:11:00:02
网桥docker0 172.17.0.1 02:42:a8:64:6c:32
虚拟机网卡enp0s3 192.168.0.11 08:00:27:70:b6:ef
在bbox1内部执行ping www.baidu.com

在docker0上抓包:
[root@docker1 ~]# tcpdump -nei docker0 icmp
listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
12:49:11.669684 02:42:ac:11:00:02 > 02:42:a8:64:6c:32, ethertype IPv4 (0x0800), length 98: 172.17.0.2 > 180.101.49.11: ICMP echo request, id 9728, seq 0, length 64
12:49:11.697374 02:42:a8:64:6c:32 > 02:42:ac:11:00:02, ethertype IPv4 (0x0800), length 98: 180.101.49.11 > 172.17.0.2: ICMP echo reply, id 9728, seq 0, length 64
在enp0s3上抓包:
[root@docker1 ~]# tcpdump -nei enp0s3 icmp
listening on enp0s3, link-type EN10MB (Ethernet), capture size 262144 bytes
12:49:11.669700 08:00:27:70:b6:ef > 48:0e:ec:3b:b3:41, ethertype IPv4 (0x0800), length 98: 192.168.0.11 > 180.101.49.11: ICMP echo request, id 9728, seq 0, length 64
12:49:11.697340 48:0e:ec:3b:b3:41 > 08:00:27:70:b6:ef, ethertype IPv4 (0x0800), length 98: 180.101.49.11 > 192.168.0.11: ICMP echo reply, id 9728, seq 0, length 64
从enp0s3的报文可以看出,源IP和MAC已经是enp0s3的了。

3.外部访问容器
3.1 创建nginx容器并从外部访问
创建一个nginx容器,执行docker run -it -d --name=nginx01 -p 8081:80 nginx该命令将容器的80端口映射到主机的8081端口。
从本虚拟机上curl 127.0.0.1:8081,能返回nginx欢迎信息。从另一台虚拟机上curl 192.168.0.11:8081,也能返回nginx欢迎信息。说明外部网络能访问nginx容器。

3.2 原理
使用了IPtables的DNAT功能。
执行iptables -t nat -vnL查看IPtables规则,可以发现目的端口8081被替换为172.17.0.4:80。

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8081 to:172.17.0.4:80
3.3 一张图总结

在Host2里面curl 192.168.0.11:8081,报文到达Host1的enp0s3;
Host1的enp0s3发出报文后,经由内核的转发及DNAT处理,将目的IP替换成nginx01的IP和端口;
docker0收到报文后,根据目的mac找到对应端口,送出报文到nginx01。
3.4 抓包
使用tcpdump,在Host1的网卡及docker0上抓包验证。

Host1的enp0s3
[root@docker1 ~]# tcpdump -nei enp0s3 tcp port 8081
listening on enp0s3, link-type EN10MB (Ethernet), capture size 262144 bytes
13:25:14.725366 08:00:27:d4:6f:d1 > 08:00:27:70:b6:ef, ethertype IPv4 (0x0800), length 74: 192.168.0.12.48392 > 192.168.0.11.tproxy: Flags [S], seq 1433025043, win 29200, options [mss 1460,sackOK,TS val 4294829465 ecr 0,nop,wscale 7], length 0
13:25:14.725559 08:00:27:70:b6:ef > 08:00:27:d4:6f:d1, ethertype IPv4 (0x0800), length 74: 192.168.0.11.tproxy > 192.168.0.12.48392: Flags [S.], seq 404119170, ack 1433025044, win 28960, options [mss 1460,sackOK,TS val 59419808 ecr 4294829465,nop,wscale 7], length 0
Host1的docker0
[root@docker1 ~]# tcpdump -nei docker0 tcp
listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
13:26:07.014766 02:42:a8:64:6c:32 > 02:42:ac:11:00:04, ethertype IPv4 (0x0800), length 74: 192.168.0.12.48396 > 172.17.0.4.http: Flags [S], seq 1839700092, win 29200, options [mss 1460,sackOK,TS val 4294881751 ecr 0,nop,wscale 7], length 0
13:26:07.015357 02:42:ac:11:00:04 > 02:42:a8:64:6c:32, ethertype IPv4 (0x0800), length 74: 172.17.0.4.http > 192.168.0.12.48396: Flags [S.], seq 3312305882, ack 1839700093, win 28960, options [mss 1460,sackOK,TS val 59472098 ecr 4294881751,nop,wscale 7], length 0
可以看出,docker0上收到的报文,目的IP及MAC已经是nginx01的了。

3.5 docker-proxy
注意:对于外部访问容器,除了iptables DNAT处理外,还有一种方式docker-proxy。网上很多文章写得并不全面,只说了docker-proxy。其实通过上面的分析,只通过DNAT就可以完成外部访问容器了,那docker-proxy什么时候起作用呢?

[root@docker1 ~]# ps -ef|grep proxy
root      4073   927  0 13:07 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8081 -container-ip 172.17.0.4 -container-port 80
root      4143  1521  0 13:32 pts/0    00:00:00 grep --color=auto proxy
查看进程可以发现,我们的host上也开启了docker-proxy,将host的0.0.0.0:8081转发到容器172.17.0.4:80。
关于docker-proxy和DNAT何时起作用,有一篇文章分析的很好,分享给大家《docker-proxy存在合理性分析》。

4.小结
容器访问外部,由iptables SNAT实现
外部访问容器,由iptables DNAT实现,另外在一些场景下,通过docker-proxy进行转发
原文地址https://www.cnblogs.com/sunqingliang/p/12731601.html

相关文章
|
18小时前
|
运维 安全 Linux
深入理解Docker自定义网络:构建高效的容器网络环境
深入理解Docker自定义网络:构建高效的容器网络环境
|
18小时前
|
存储 弹性计算 运维
Docker数据集与自定义镜像:构建高效容器的关键要素
Docker数据集与自定义镜像:构建高效容器的关键要素
|
20小时前
|
Kubernetes Java 调度
Java容器技术:Docker与Kubernetes
Java容器技术:Docker与Kubernetes
7 0
|
1天前
|
算法 计算机视觉 Docker
Docker容器中的OpenCV:轻松构建可移植的计算机视觉环境
Docker容器中的OpenCV:轻松构建可移植的计算机视觉环境
Docker容器中的OpenCV:轻松构建可移植的计算机视觉环境
|
1天前
|
存储 Prometheus 监控
【Docker 专栏】Docker 容器内应用的调试与故障排除
【5月更文挑战第8天】本文探讨了Docker容器内应用的调试与故障排除,强调其重要性。方法包括:通过日志排查、进入容器检查、使用监控工具及检查容器配置。常见问题涉及应用启动失败、性能问题、网络连接和数据存储。案例分析展示了实战场景,注意事项提醒避免不必要的容器修改、备份数据和理解应用架构。掌握这些技能能确保Docker应用的稳定运行和性能优化。
【Docker 专栏】Docker 容器内应用的调试与故障排除
|
1天前
|
负载均衡 网络协议 算法
【Docker 专栏】Docker 容器内服务发现与负载均衡
【5月更文挑战第8天】本文探讨了Docker容器中的服务发现与负载均衡。服务发现通过环境变量、DNS或集中式系统(如Consul、Zookeeper)来定位服务实例。负载均衡则采用轮询、随机等算法,可通过软件负载均衡器、云服务或容器编排工具(如Kubernetes)实现。服务发现与负载均衡结合使用,确保请求有效分发和系统稳定性。面对动态性、网络延迟及大规模部署的挑战,需采取相应措施优化。选择合适技术并持续优化,能提升Docker容器应用的性能和可靠性。
【Docker 专栏】Docker 容器内服务发现与负载均衡
|
1天前
|
存储 安全 数据中心
【Docker 专栏】Docker 容器与宿主机的资源隔离机制
【5月更文挑战第8天】Docker容器利用Namespace和Cgroups实现资源隔离,保证CPU、内存、网络和存储的独立,提升资源利用率和系统安全性。资源隔离有助于简化应用部署与管理,但也带来资源竞争、监控管理及安全挑战。理解并善用资源隔离机制能实现更高效、安全的容器运行。随着技术进步,Docker容器资源隔离将持续优化。
【Docker 专栏】Docker 容器与宿主机的资源隔离机制
|
1天前
|
运维 Linux Docker
Docker详解(十三)——Docker容器的内存和磁盘I/O限制配置
Docker详解(十三)——Docker容器的内存和磁盘I/O限制配置
8 1
|
1天前
|
存储 缓存 监控
【Docker 专栏】Docker 容器性能调优实战
【5月更文挑战第8天】本文探讨了Docker容器的性能调优技巧,包括理解容器性能指标(如CPU、内存、网络和磁盘I/O)并进行相应调优。重点讲述了CPU和内存的限制设置,网络配置优化以及磁盘I/O性能提升方法。通过实例展示了如何解决高CPU使用率问题,强调了根据应用需求进行调优的重要性,以实现更高效、稳定的容器运行。
【Docker 专栏】Docker 容器性能调优实战
|
1天前
|
存储 应用服务中间件 Docker
Docker容器无法启动Cannot find /usr/local/tomcat/bin/setclasspath.sh
根据具体情况,你可以尝试以上方法中的一个或多个,以解决 "Cannot find /usr/local/tomcat/bin/setclasspath.sh" 的问题。确保你的Docker容器中包含了完整且正确配置的Tomcat,并且相关文件和目录的权限设置正确。
7 0