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进行转发
下一节,我们介绍bridge network的自定义网络。 点击此处回到docker系列文章目录。
原创文章,转载请声明出处!
-----------------------------------------------------------------------------------------------
本人微信公众号同步更新云计算、容器、网络、编程等文章,欢迎参观!
Docker-Bridge Network 02 容器与外部通信的更多相关文章
- Docker:macvlan实现容器跨主机通信 [十四]
一.什么是macvlan 1.macvlan 本身是 linux kernel 模块,其功能是允许在同一个物理网卡上配置多个 MAC 地址, 2.即多个 interface,每个 interface ...
- Docker容器跨主机通信之:直接路由方式
一.Docker网络基本原理 直观上看,要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)与外界相通,并可以收发数据包:此外,如果不同子网之间要进行通信,需要额外的路由机制. Docker ...
- centos7下安装docker(15.5容器跨主机网络--flanneld)
flannel是由CoreOS研究的一种覆盖网络(overlay network)网络工具,目的是帮助每一个host主机有一个完整的子网: 功能是:让集群中不同节点的主机创建的容器都有一个唯一的虚拟I ...
- AspNetCore容器化(Docker)部署(二) —— 多容器通信
一.前言 着上一篇 AspNetCore容器化(Docker)部署(一) —— 入门,在单个容器helloworld的基础上引入nginx反向代理服务器组成多容器应用. 二.配置反向代理转接 配置转接 ...
- Docker-Bridge Network 01 容器间通信
本小节介绍bridge network模式下,单机上的容器网络拓扑及通信. 1.前言 对于单机上的容器,Docker提供了bridge.host.none三种网络.我们首先介绍经典的bridge模式. ...
- Docker容器跨主机通信--overlay网络
一.Docker主机间容器通信的解决方案 Docker网络驱动 Overlay: 基于VXLAN封装实现Docker原生Overlay网络 Macvlan: Docker主机网卡接口逻辑上分为多个子接 ...
- Docker 网络管理及容器跨主机通信
1.网络模式 docker支持四种网络模式,使用--net选项指定: host,--net=host,如果指定此模式,容器将不会获得一个独立的network namespace,而是和宿主机共用一个. ...
- docker容器之间的通信
容器之间互通 新建两个容器 docker run -d --name box1 busybox /bin/sh -c "while true;do sleep 3600;done" ...
- (转)Docker - 创建 Docker overlay network (containers 通信)
原文链接: http://www.cnblogs.com/AlanWalkOn/p/6101875.html --- 创建基于Key-Value的Docker overlay network. 这样运 ...
随机推荐
- Andorid 添加MenuPopup
- Scapy编写UDP扫描脚本
脚本内容如下: from scapy.all import * import optparse import threading def scan(target,port): pkt=IP(dst=t ...
- Cisco 综合配置(二)
要求: 1. PC1 属于VLAN10,PC2属于VLAN20,网关:Master Router2. VLAN10.20 的网段为:192.168.10.0/24 . 192.168.20.0/24 ...
- zabbix笔记_008 zabbix监控交换机路由器
zabbix监控交换机路由器 要监控路由器交换机,需要使用到SNMP协议 SNMP是一个简单网络管理协议,他基于C/S模型实现的监控和管理. 服务器安装SNMP: yum -y install net ...
- POJ 1182食物链(分集合以及加权两种解法) 种类并查集的经典
题目链接:http://icpc.njust.edu.cn/Problem/Pku/1182/ 题意:给出动物之间的关系,有几种询问方式,问是真话还是假话. 定义三种偏移关系: x->y 偏移量 ...
- 一起学习vue源码 - Vue2.x的生命周期(初始化阶段)
作者:小土豆biubiubiu 博客园:https://www.cnblogs.com/HouJiao/ 掘金:https://juejin.im/user/58c61b4361ff4b005d9e8 ...
- OpenCV-Python 相机校准 | 四十九
目标 在本节中,我们将学习 由相机引起的失真类型, 如何找到相机的固有和非固有特性 如何根据这些特性使图像不失真 基础 一些针孔相机会给图像带来明显的失真.两种主要的变形是径向变形和切向变形. 径向变 ...
- GANs和低效映射
生成对抗网络(GANs)被誉为生成艺术领域的下一纪元,这是有充分理由的.新技术一直是艺术的驱动因素,从颜料的发明到照相机再到Photoshop-GAN是自然而然的.例如,考虑下面的图片,由埃尔加马勒发 ...
- 使用Keras进行深度学习:(五)RNN和双向RNN讲解及实践
欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/,学习更多的机器学习.深度学习的知识! 笔者:Ray 介绍 通过对前面文章的学习,对深度神经网络(DNN) ...
- 【Pytest03】全网最全最新的Pytest框架fixture应用篇(1)
fixtrue修饰器标记的方法通常用于在其他函数.模块.类或者整个工程调用时会优先执行,通常会被用于完成预置处理和重复操作.例如:登录,执行SQL等操作. 完整方法如下:fixture(scope=' ...