Docker容器访问外部世界

Docker网络(host、bridge、none)详细介绍

Docker容器间通信

前面我们已经解决了容器间通信的问题,接下来讨论容器如何与外部世界通信。

这里涉及两个方向:

(1)容器访问外部世界。

(2)外部世界访问容器。

容器访问外部世界

在我们当前的实验环境下,docker host是可以访问外网的

我们看一下容器是否也能访问外网呢?

可见,容器默认就能访问外网。
请注意:这里外网指的是容器网络以外的网络环境,并非特指Internet.

现象很简单,但更重要的:我们应该理解现象下的本质。


在上面的例子中,busybox位于dockero这个私有bridge网络中(172.17.0.0/16),当busybox从容器向外ping时,数据包是怎样到达bing.com的呢?


这里的关键就是NAT,我们查看一下docker host上的iptables规则

在NAT表中,有这么一条规则:

-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

其含义是:如果网桥docker0收到来自172.17.0.0/16网段的外出包,把它交给MASQUERADE处理。而且MASQUERADE的处理方式是将

包的原地址替换成host的地址发送出去,机 做了一次网络地址转换(NAT)


下面我们通过tcpdump查看地址是如何转换的。先查看docker host的路由表

默认路由通过ens192发出去,所以我们同时要监控ens192和docker0上的icmp(ping)的数据包。

当busybox ping www.baidu.com时,tcpdumo输出如下

tcpdump -i docker0 -n icmp

docker0收到busybox的ping包,源地址为容器的IP:172.17.0.2,这没问题,交给MASQUERADE处理。这时,在看ens192的变化。

ping包的源地址变成ens192的192.168.1.100

这就是iptables的NAT规则的处理结果,从而保证数据包能够到达外网。

下面这张图来说明结果。

  • (1)busybox发送ping包:172.17.0.2 > www.bing.com。
  • (2)dockero收到包,发现是发送到外网的,交给NAT处理。
  • (3)NAT将源地址换成ens192的IP:10.0.2.15 >www.bing.com.
  • (4)ping从 ens192出去,达www.bing.como

通过NAT,docker实现了容器对外网的访问。

 

外部世界访问容器

下面我们来讨论另一个方向:外网如何访问到容器?
答案是:端口映射。


docker可将容器对外提供服务的端口映射到host的某个端口,外网通过该端口访问容器。容器启动时通过-p参数映射端口

[root@kvm ~]# docker run -d -p 80 httpd
6b89d7e3f47a425256af6934689c0009fbbad9099bf31c2e6148a6cb236a9655
[root@kvm ~]# docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
6b89d7e3f47a        httpd               "httpd-foreground"   5 seconds ago       Up 2 seconds        0.0.0.0:32768->80/tcp   stoic_bartik
78de9710bce0        busybox             "sh"                 19 minutes ago      Up 19 minutes                               hei
[root@kvm ~]# docker port 6b89d7e3f47a
80/tcp -> 0.0.0.0:32768

容器启动后,可通过docker ps或者docker port查看到host映射的端口。在上面的例子中,httpd容器的80端口被映射到host 32768上,这样就可以通过<host ip>:<32773>访问容器的Web服务了

除了映射动态端口,也可在-p中指定映射到host某个特定端口,例如可将80端口映射到host的8080端口

[root@kvm ~]# docker run -d -p 8080:80 httpd
8d7db7b2c7a6fc03cd219d6d3c07f15261d8a12efda3be25fdb60576c91c1a7e
[root@kvm ~]# curl 192.168.1.100:8080
<html><body><h1>It works!</h1></body></html>
[root@kvm ~]# 

每一个映射的端口,host都会启动一个docker-proxy进程来处理访问容器的流量。

以0.0.0.0:32773-280/tcp为例分析整个过程

  • (1)docker-proxy监听host的32773端口。
  • (2)当curl访问10.0.2.15:32773时,docker-proxy转发给容器172.170.2:80。
  • (3)httpd容器响应请求并返回结果。

 

posted @ 2020-03-20 16:38  南宫乘风  阅读(17213)  评论(1编辑  收藏  举报