centos7下安装docker(12.4容器如何与外部进行通信)
1.容器如何访问外部
前面我们做了很多试验:只要host能连外网,使用默认bridge(docker0)创建得容器就能访问外网,那么容器是怎样访问外网的呢?
注:这里的外网不仅是internet,包括internet
容器是怎样访问外网的呢?
这里的关键就是NAT。我们查看一下docker host上的iptables的规则
可以看到iptables对docker0这个bridge做了策略:当网桥docker0收到外出的包,把他交给MASQUERADE处理。而MASQUERADE的处理方式是将包的源地址替换成host地址发送出去,即做了一次网络地址转换(NAT)
我们可以通过tcpdump查看地址如何转换。先查看docker host的路由表:(此试验我开了三个终端)
默认路由通过ens160(host网卡) 发出去的,所以我们要同时监控ens160和docker0上的icmp(ping)数据包
源地址容器发送请求
docker0接收到源地址的请求,docker0将请求交给MASQURADE进行处理
我们可以看到ens160的变化:MASQUERADE将源地址的包转换成Host的地址,发送出去(这就是NAT的网络地址转换,深刻理解了)
这就是iptables NAT规则的处理结果,从而保证数据包能到达外网
继续盗图:
处理过程:1.容器发送ping包:172.17.0.5>www.baidu.com
2.docker0收到包后,发现是发送到外网的。交给NAT处理
3.NAT将源地址转换成ens160的IP:192.168.7.222>www.baidu.com
4.ping包从ens160发出去。到达www.baidu.com
通过NAT,docker容器实现了对外网的访问。
2.外部访问容器:端口映射
docker将容器对外提供服务的端口映射到host的某个端口,外网通过该端口访问容器。容器启动时通过-p映射端口
之前我们学习制作私有仓库的时候registry:docker run -d -p 5000:5000 -v /myregistry:/var/lib/docker registry
我们可以通过docker ps 和docker port来查看端口映射,上面的例子中,httpd容器的端口80,被映射到host32768上,这样就可以通过<host ip>:<32768>来访问容器的web服务,但是这个32768我们并没有指定,是怎么来的呢?
可以看出是在没指定的情况下,这个端口是host随机分配的一个,这叫动态映射
在host上可以看到32768这个端口已经被监听了,我们来试验一下外网能否访问到web
是可以访问的
除了动态映射,我们也可以在-p中指定映射到host某个特定端口,例如将80映射到host的8080
每一个端口映射,host都会启动一个docker-proxy进程来处理访问容器的流量
再盗一图:
我们以0.0.0.0:32768->80为例子,来分析整个过程
1.当外网访问<host ip>:<32768>时,docker-proxy监听到host的32768端口有请求
2.docker-proxy将请求转发给对应的容器172.17.0.7:80
3.容器接收到请求后响应请求并返回结果。
总结:本节深刻理解了NAT网络地址转换,知道容器是通过NAT访问外网的;外网访问容器的时候,是通过-p设置端口映射实现的,设置了容器的端口映射后,host会为每个容器对应的端口启动一个docker-proxy来监听host上对应端口,并将请求转发给容器进行处理。通过容器的动态映射,可以体会到,host的端口是唯一的,也就是说当32768已经存在的时候,就不能再映射一个32768端口到host上。docker-proxy能保持容器和host上的映射保持一一对应。