网络端口映射的原理
docker有容器内外的端口映射,是怎么做到的呢?这是要起一个新的网络的namespace吧;
启动了docker之后,在docker上面还是有确实是有iptables的项,但是此时应该是有两个网络的namespace吧,使用ip netns list是没有看到的,也就是说其实是在一个网络的namespace中的网络端口的映射;
Chain POSTROUTING (policy ACCEPT) target prot opt source destination MASQUERADE all -- 172.17.0.0/16 anywhere MASQUERADE tcp -- 172.17.0.2 172.17.0.2 tcp dpt:1234 Chain DOCKER (2 references) target prot opt source destination RETURN all -- anywhere anywhere DNAT tcp -- anywhere anywhere tcp dpt:32769 to:172.17.0.2:1234
在iptables的输出中有如上的两条规则,然后docker会启动一个proxy:
/usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 32769 -container-ip 172.17.0.2 -container-port 1234
把收到的tcp包透传给容器?
这种端口的映射在内核里做个转化就好了吧?0.0.0.0:32769 –> 172.17.0.2:1234
系统中多了这样一张网卡:
veth485dee9 Link encap:以太网 硬件地址 f2:c6:f3:6c:4f:7a
inet6 地址: fe80::f0c6:f3ff:fe6c:4f7a/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 跃点数:1
接收数据包:14 错误:0 丢弃:0 过载:0 帧数:0
发送数据包:46 错误:0 丢弃:0 过载:0 载波:0
碰撞:0 发送队列长度:0
接收字节:1088 (1.0 KB) 发送字节:4987 (4.9 KB)
这里就是个veth设备了,容器内外各有一个,从容器中来的数据直接就导流到了网桥上
==========
启动了多个docker,
ip netns list 看到的内容和 ip netns list-id看到的内容为啥不是一样的?
如果多个容器把自己的都绑定到宿主机的8080端口咋样?不能做,本地的端口已经被映射掉了;也就是说,不可能实现,同一台主机两个容器内同时监听8080端口;回到原来的问题上,创建一个
ip netns list是从/var/run/netns中去读取内容,但是现在如果没有内容呢?
内核是如何查看网络的参数的? man ip-netns
ip netns list-id - list network namespace ids (nsid) Network namespace ids are used to identify a peer network namespace. This command displays nsid of the current network namespace and provides the corresponding iproute2 netns name (from /var/run/netns) if any.
看下这个命令是干嘛的? network namespace ids(nsid) 列出系统中所有的peer网络ns,如果这个对等网络有名字,那么会列出名字;所以ip netns list-id中所有的明明空间呢;
所以命名空间分为两类:named network namespace & peer network namespace [不纠结这个小事了,因为从/proc/<pid>/ns/net看确实是不同的网络的命名空间了]
下面看在宿主机上如何完成端口的映射;使用iptables;
想下之前的nat的设置,都是在postrouting时转换网络的IP地址,然后在接收到数据包时,系统会用自动生成的reverse功能把数据包给转回来,这样的话宿主机内的路由就会把这包送给容器内地址了【这里有个小gap:宿主机什么时候决定丢包?
step1:收到数据包,发现数据包是本地地址,保留;
step2:然后更换数据包的目的地址;
step3:进入本机的路由;【是哪个参数可以本机路由了呢?ipv4.ip_forward=1?】在协议栈里面是如何处理的呢?是否真的有本机路由这件事情? 从wireshark看确实是有的,这一点是wuyongzhiyi.
//外面的机器不应该能访问到我本机器上的一台虚拟机,因为这台虚拟机是我内网的,要保护起来,现在的各种NAT机制也不支持;但是我这台docker虚拟机是可以对外提供服务的呀;比如所有对1000号端口的访问都引流到我这台机器上就好啦:https://www.cnblogs.com/jjzd/p/6505871.html
作如下试验:网络拓扑结构
树莓派 A:
主机PC B:
主机上docker容器: C:
sudo iptables -t nat -A PREROUTING -d [B地址] -p tcp -m tcp --dport 10000 -j DNAT --to-destination 【容器C地址】:10000