(转)外网如何访问docker容器

﹥>﹥吖頭↗ 提交于 2021-01-09 08:57:08

借鉴:https://blog.csdn.net/lvshaorong/article/details/69950694

<div class="htmledit_views" id="content_views"> <p>Docker容器非常轻量,系统开销非常少,比VMware或者<a href="https://www.baidu.com/s?wd=VirtualBox&amp;tn=24004469_oem_dg&amp;rsv_dl=gh_pl_sl_csd" target="_blank">VirtualBox</a>用起来方便,部署起来也非常容易。官方推荐我们通过端口映射的方式把Docker容器的服务提供给宿主机或者局域网其他容器使用。一般过程是:</p><p>1、Docker进程通过监听宿主机的某个端口,将该端口的数据包发送给Docker容器</p><p>2、宿主机可以打开防火墙让局域网其他设备通过访问宿主机的端口进而访问docker的端口</p><p>这里以CDNS为例,CDNS是一个用于避免DNS污染的程序,通过CDNS可以把你的计算机变成一个抗污染的DNS服务器提供给局域网使用。Docker镜像下载地址:https://hub.docker.com/r/alexzhuo/cdns/</p><p><br></p><p>原理是在Docker容器中启动CDNS,监听53端口,Docker容器的IP地址为172.12.0.2,宿主机把5053端口映射到Docker容器上,访问宿主机的<a href="https://www.baidu.com/s?wd=127.0.0.1&amp;tn=24004469_oem_dg&amp;rsv_dl=gh_pl_sl_csd" target="_blank">127.0.0.1</a>:5053就相当于访问Docker的53端口,所以Docker的启动方法是:</p><p></p><pre><code class="language-swift">sudo docker run -itd -p <span class="hljs-number">0.0</span>.<span class="hljs-number">0.0</span>:<span class="hljs-number">5053</span>:<span class="hljs-number">53</span>/udp --name=<span class="hljs-type">CureDNS</span> alexzhuo/cdns cdns -<span class="hljs-built_in">c</span> /etc/cdns.config.json</code></pre><br>这样我们使用dig工具通过5053端口查询DNS就是无污染的DNS了,过程如下:<p></p><p></p><pre><code class="language-ruby">alex@alex-Lenovo-<span class="hljs-symbol">U310:</span>~$ dig www.facebook.com @127.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">1</span> -p <span class="hljs-number">5053</span>

; DiG <span class="hljs-number">9.10</span>.<span class="hljs-number">3</span>-P4-Ubuntu <<<span class="hljs-meta">>> </span>www.facebook.com @127.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">1</span> -p <span class="hljs-number">5053</span> ;; global <span class="hljs-symbol">options:</span> +cmd ;; Got <span class="hljs-symbol">answer:</span> ;; -<span class="hljs-meta">>></span>HEADER<<- <span class="hljs-symbol">opcode:</span> QUERY, <span class="hljs-symbol">status:</span> NOERROR, <span class="hljs-symbol">id:</span> <span class="hljs-number">9522</span> ;; <span class="hljs-symbol">flags:</span> qr rd ra; <span class="hljs-symbol">QUERY:</span> <span class="hljs-number">1</span>, <span class="hljs-symbol">ANSWER:</span> <span class="hljs-number">2</span>, <span class="hljs-symbol">AUTHORITY:</span> <span class="hljs-number">2</span>, <span class="hljs-symbol">ADDITIONAL:</span> <span class="hljs-number">5</span>

;; OPT <span class="hljs-symbol">PSEUDOSECTION:</span> ; <span class="hljs-symbol">EDNS:</span> <span class="hljs-symbol">version:</span> <span class="hljs-number">0</span>, <span class="hljs-symbol">flags:</span>; <span class="hljs-symbol">udp:</span> <span class="hljs-number">4096</span> ;; QUESTION <span class="hljs-symbol">SECTION:</span> ;www.facebook.com. IN A

;; ANSWER <span class="hljs-symbol">SECTION:</span> www.facebook.com. <span class="hljs-number">1550</span> IN CNAME star-mini.c10r.facebook.com. star-mini.c10r.facebook.com. <span class="hljs-number">30</span> IN A <span class="hljs-number">31.13</span>.<span class="hljs-number">95.36</span>

;; AUTHORITY <span class="hljs-symbol">SECTION:</span> c10r.facebook.com. <span class="hljs-number">2010</span> IN NS a.ns.c10r.facebook.com. c10r.facebook.com. <span class="hljs-number">2010</span> IN NS b.ns.c10r.facebook.com.

;; ADDITIONAL <span class="hljs-symbol">SECTION:</span> a.ns.c10r.facebook.com. <span class="hljs-number">2439</span> IN A <span class="hljs-number">69.171</span>.<span class="hljs-number">239.11</span> a.ns.c10r.facebook.com. <span class="hljs-number">2439</span> IN AAAA <span class="hljs-number">2</span><span class="hljs-symbol">a03:</span><span class="hljs-number">2880</span><span class="hljs-symbol">:fffe</span><span class="hljs-symbol">:b</span><span class="hljs-symbol">:face</span><span class="hljs-symbol">:b00c</span><span class="hljs-symbol">:</span><span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">99</span> b.ns.c10r.facebook.com. <span class="hljs-number">3351</span> IN A <span class="hljs-number">69.171</span>.<span class="hljs-number">255.11</span> b.ns.c10r.facebook.com. <span class="hljs-number">1253</span> IN AAAA <span class="hljs-number">2</span><span class="hljs-symbol">a03:</span><span class="hljs-number">2880</span><span class="hljs-symbol">:ffff</span><span class="hljs-symbol">:b</span><span class="hljs-symbol">:face</span><span class="hljs-symbol">:b00c</span><span class="hljs-symbol">:</span><span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">99</span>

;; Query <span class="hljs-symbol">time:</span> <span class="hljs-number">47</span> msec ;; <span class="hljs-symbol">SERVER:</span> <span class="hljs-number">127.0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">1</span><span class="hljs-comment">#5053(127.0.0.1)</span> ;; <span class="hljs-symbol">WHEN:</span> Mon Apr <span class="hljs-number">10</span> <span class="hljs-number">16</span><span class="hljs-symbol">:</span><span class="hljs-number">21</span><span class="hljs-symbol">:</span><span class="hljs-number">46</span> CST <span class="hljs-number">2017</span> ;; MSG SIZE <span class="hljs-symbol">rcvd:</span> <span class="hljs-number">213</span> </code></pre><br>这里假设我们的宿主机IP是192.168.12.107<p></p><p>如果现在出现另外一台局域网计算机,IP地址为192.168.12.113,它想把宿主机当成DNS服务器,那么我们就需要在192.168.12.113这台计算机上访问192.168.12.107:5053来查询DNS,dig命令如下</p><p></p><pre><code class="language-css"><span class="hljs-selector-tag">dig</span> <span class="hljs-selector-tag">www</span><span class="hljs-selector-class">.facebook</span><span class="hljs-selector-class">.com</span> @<span class="hljs-keyword">192</span>.<span class="hljs-keyword">168</span>.<span class="hljs-keyword">12</span>.<span class="hljs-keyword">107</span> -p <span class="hljs-number">5053</span></code></pre><br>这样做显然是很不方便的,我们现在希望不经过宿主机这一套NAT和代理,想要直接在局域网内的任意一台计算机上直接通过IP访问Docker容器,让Docker容器完整的暴露在局域网里而不是仅单单暴露一个53端口。那么应该如何做呢?<p></p><p><br></p><p>首先通过观察发现,Docker的默认启动方式中,会产生一块虚拟网卡,在这里我们可以理解这块网卡连接着一个<a href="https://www.baidu.com/s?wd=%E8%99%9A%E6%8B%9F%E4%BA%A4%E6%8D%A2%E6%9C%BA&amp;tn=24004469_oem_dg&amp;rsv_dl=gh_pl_sl_csd" target="_blank">虚拟交换机</a>,然后每个Docker容器又会拥有自己单独的网卡和IP,而且所有Docker容器也连接在这个虚拟交换机的下面。我们可以在宿主机上通过ifconfig命令看到这个虚拟网卡。</p><p></p><pre><code class="language-ruby">alex@alex-Lenovo-<span class="hljs-symbol">U310:</span>~$ ifconfig docker<span class="hljs-number">0</span> Link <span class="hljs-symbol">encap:</span>以太网 硬件地址 <span class="hljs-number">02</span><span class="hljs-symbol">:</span><span class="hljs-number">42</span><span class="hljs-symbol">:cd</span><span class="hljs-symbol">:</span><span class="hljs-number">21</span><span class="hljs-symbol">:</span><span class="hljs-number">5</span><span class="hljs-symbol">c:</span><span class="hljs-number">81</span>
inet 地址<span class="hljs-symbol">:</span><span class="hljs-number">172.17</span>.<span class="hljs-number">0</span>.<span class="hljs-number">1</span> 广播<span class="hljs-symbol">:</span><span class="hljs-number">0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span> 掩码<span class="hljs-symbol">:</span><span class="hljs-number">255.255</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span> inet6 地址: fe80::<span class="hljs-number">42</span><span class="hljs-symbol">:cdff</span><span class="hljs-symbol">:fe21</span><span class="hljs-symbol">:</span><span class="hljs-number">5</span>c81/<span class="hljs-number">64</span> <span class="hljs-symbol">Scope:</span>Link UP BROADCAST RUNNING MULTICAST <span class="hljs-symbol">MTU:</span><span class="hljs-number">1500</span> 跃点数<span class="hljs-symbol">:</span><span class="hljs-number">1</span> 接收数据包<span class="hljs-symbol">:</span><span class="hljs-number">2892</span> 错误<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 丢弃<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 过载<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 帧数<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 发送数据包<span class="hljs-symbol">:</span><span class="hljs-number">3517</span> 错误<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 丢弃<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 过载<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 载波<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 碰撞<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 发送队列长度<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 接收字节<span class="hljs-symbol">:</span><span class="hljs-number">187022</span> (<span class="hljs-number">187.0</span> KB) 发送字节<span class="hljs-symbol">:</span><span class="hljs-number">4771886</span> (<span class="hljs-number">4.7</span> MB)

lo Link <span class="hljs-symbol">encap:</span>本地环回
inet 地址<span class="hljs-symbol">:</span><span class="hljs-number">127.0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">1</span> 掩码<span class="hljs-symbol">:</span><span class="hljs-number">255.0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span> inet6 地址: <span class="hljs-symbol">:</span><span class="hljs-symbol">:</span><span class="hljs-number">1</span>/<span class="hljs-number">128</span> <span class="hljs-symbol">Scope:</span>Host UP LOOPBACK RUNNING <span class="hljs-symbol">MTU:</span><span class="hljs-number">65536</span> 跃点数<span class="hljs-symbol">:</span><span class="hljs-number">1</span> 接收数据包<span class="hljs-symbol">:</span><span class="hljs-number">9993</span> 错误<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 丢弃<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 过载<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 帧数<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 发送数据包<span class="hljs-symbol">:</span><span class="hljs-number">9993</span> 错误<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 丢弃<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 过载<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 载波<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 碰撞<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 发送队列长度<span class="hljs-symbol">:</span><span class="hljs-number">1</span> 接收字节<span class="hljs-symbol">:</span><span class="hljs-number">934304</span> (<span class="hljs-number">934.3</span> KB) 发送字节<span class="hljs-symbol">:</span><span class="hljs-number">934304</span> (<span class="hljs-number">934.3</span> KB)

wlp3s<span class="hljs-number">0</span> Link <span class="hljs-symbol">encap:</span>以太网 硬件地址 <span class="hljs-number">74</span><span class="hljs-symbol">:e5</span><span class="hljs-symbol">:</span><span class="hljs-number">43</span><span class="hljs-symbol">:b0</span><span class="hljs-symbol">:dd</span><span class="hljs-symbol">:b0</span>
inet 地址<span class="hljs-symbol">:</span><span class="hljs-number">192.168</span>.<span class="hljs-number">12.107</span> 广播<span class="hljs-symbol">:</span><span class="hljs-number">192.168</span>.<span class="hljs-number">12.255</span> 掩码<span class="hljs-symbol">:</span><span class="hljs-number">255.255</span>.<span class="hljs-number">255.0</span> inet6 地址: fe80::<span class="hljs-number">8</span><span class="hljs-symbol">adf:</span><span class="hljs-number">28</span><span class="hljs-symbol">f7:</span><span class="hljs-number">5</span><span class="hljs-symbol">ec:</span><span class="hljs-number">3</span>a5d/<span class="hljs-number">64</span> <span class="hljs-symbol">Scope:</span>Link UP BROADCAST RUNNING MULTICAST <span class="hljs-symbol">MTU:</span><span class="hljs-number">1500</span> 跃点数<span class="hljs-symbol">:</span><span class="hljs-number">1</span> 接收数据包<span class="hljs-symbol">:</span><span class="hljs-number">69760</span> 错误<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 丢弃<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 过载<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 帧数<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 发送数据包<span class="hljs-symbol">:</span><span class="hljs-number">64718</span> 错误<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 丢弃<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 过载<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 载波<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 碰撞<span class="hljs-symbol">:</span><span class="hljs-number">0</span> 发送队列长度<span class="hljs-symbol">:</span><span class="hljs-number">1000</span> 接收字节<span class="hljs-symbol">:</span><span class="hljs-number">41517057</span> (<span class="hljs-number">41.5</span> MB) 发送字节<span class="hljs-symbol">:</span><span class="hljs-number">9971762</span> (<span class="hljs-number">9.9</span> MB) </code></pre><br>上面的docker0这块网卡就是虚拟网卡,它的IP地址是172.17.0.1,它和其他的docker容器都连接在一个虚拟交换机上,网段为172.17.0.0/16,下面我们登录到Docker容器里面,查看一下容器的网卡和IP<p></p><p></p><pre><code class="language-ruby"><span class="hljs-comment"># ifconfig</span> eth<span class="hljs-number">0</span> Link <span class="hljs-symbol">encap:</span>Ethernet HWaddr <span class="hljs-number">02</span><span class="hljs-symbol">:</span><span class="hljs-number">42</span><span class="hljs-symbol">:ac</span><span class="hljs-symbol">:</span><span class="hljs-number">11</span><span class="hljs-symbol">:</span><span class="hljs-number">00</span><span class="hljs-symbol">:</span><span class="hljs-number">02</span>
inet <span class="hljs-symbol">addr:</span><span class="hljs-number">172.17</span>.<span class="hljs-number">0</span>.<span class="hljs-number">2</span> <span class="hljs-symbol">Bcast:</span><span class="hljs-number">0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span> <span class="hljs-symbol">Mask:</span><span class="hljs-number">255.255</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span> inet6 <span class="hljs-symbol">addr:</span> fe80::<span class="hljs-number">42</span><span class="hljs-symbol">:acff</span><span class="hljs-symbol">:fe11</span><span class="hljs-symbol">:</span><span class="hljs-number">2</span>/<span class="hljs-number">64</span> <span class="hljs-symbol">Scope:</span>Link UP BROADCAST RUNNING MULTICAST <span class="hljs-symbol">MTU:</span><span class="hljs-number">1500</span> <span class="hljs-symbol">Metric:</span><span class="hljs-number">1</span> RX <span class="hljs-symbol">packets:</span><span class="hljs-number">3449</span> <span class="hljs-symbol">errors:</span><span class="hljs-number">0</span> <span class="hljs-symbol">dropped:</span><span class="hljs-number">0</span> <span class="hljs-symbol">overruns:</span><span class="hljs-number">0</span> <span class="hljs-symbol">frame:</span><span class="hljs-number">0</span> TX <span class="hljs-symbol">packets:</span><span class="hljs-number">2811</span> <span class="hljs-symbol">errors:</span><span class="hljs-number">0</span> <span class="hljs-symbol">dropped:</span><span class="hljs-number">0</span> <span class="hljs-symbol">overruns:</span><span class="hljs-number">0</span> <span class="hljs-symbol">carrier:</span><span class="hljs-number">0</span> <span class="hljs-symbol">collisions:</span><span class="hljs-number">0</span> <span class="hljs-symbol">txqueuelen:</span><span class="hljs-number">0</span> RX <span class="hljs-symbol">bytes:</span><span class="hljs-number">4763490</span> (<span class="hljs-number">4.7</span> MB) TX <span class="hljs-symbol">bytes:</span><span class="hljs-number">219998</span> (<span class="hljs-number">219.9</span> KB)

lo Link <span class="hljs-symbol">encap:</span>Local Loopback
inet <span class="hljs-symbol">addr:</span><span class="hljs-number">127.0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">1</span> <span class="hljs-symbol">Mask:</span><span class="hljs-number">255.0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span> inet6 <span class="hljs-symbol">addr:</span> <span class="hljs-symbol">:</span><span class="hljs-symbol">:</span><span class="hljs-number">1</span>/<span class="hljs-number">128</span> <span class="hljs-symbol">Scope:</span>Host UP LOOPBACK RUNNING <span class="hljs-symbol">MTU:</span><span class="hljs-number">65536</span> <span class="hljs-symbol">Metric:</span><span class="hljs-number">1</span> RX <span class="hljs-symbol">packets:</span><span class="hljs-number">0</span> <span class="hljs-symbol">errors:</span><span class="hljs-number">0</span> <span class="hljs-symbol">dropped:</span><span class="hljs-number">0</span> <span class="hljs-symbol">overruns:</span><span class="hljs-number">0</span> <span class="hljs-symbol">frame:</span><span class="hljs-number">0</span> TX <span class="hljs-symbol">packets:</span><span class="hljs-number">0</span> <span class="hljs-symbol">errors:</span><span class="hljs-number">0</span> <span class="hljs-symbol">dropped:</span><span class="hljs-number">0</span> <span class="hljs-symbol">overruns:</span><span class="hljs-number">0</span> <span class="hljs-symbol">carrier:</span><span class="hljs-number">0</span> <span class="hljs-symbol">collisions:</span><span class="hljs-number">0</span> <span class="hljs-symbol">txqueuelen:</span><span class="hljs-number">1</span> RX <span class="hljs-symbol">bytes:</span><span class="hljs-number">0</span> (<span class="hljs-number">0</span>.<span class="hljs-number">0</span> B) TX <span class="hljs-symbol">bytes:</span><span class="hljs-number">0</span> (<span class="hljs-number">0</span>.<span class="hljs-number">0</span> B) </code></pre><br>可以看到这个容器的IP地址为172.17.0.2,现在我们到宿主机里看看ping 172.17.0.2能不能ping通。<p></p><p>答案当然是能ping通,能ping通的原因就是我们的宿主机里知道目标地址为172.17.0.1/16的路由信息,不信我们可以查看一下</p><p></p><pre><code class="language-perl">alex@alex-Lenovo-U31<span class="hljs-number">0</span>:~$ ip route default via <span class="hljs-number">192.168</span>.<span class="hljs-number">12.1</span> dev wlp3s<span class="hljs-number">0</span> proto static metric <span class="hljs-number">600</span> <span class="hljs-number">169.254</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>/<span class="hljs-number">16</span> dev docker<span class="hljs-number">0</span> scope <span class="hljs-keyword">link</span> metric <span class="hljs-number">1000</span> <span class="hljs-number">172.17</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>/<span class="hljs-number">16</span> dev docker<span class="hljs-number">0</span> proto kernel scope <span class="hljs-keyword">link</span> src <span class="hljs-number">172.17</span>.<span class="hljs-number">0</span>.<span class="hljs-number">1</span> <span class="hljs-number">192.168</span>.<span class="hljs-number">12.0</span>/<span class="hljs-number">24</span> dev wlp3s<span class="hljs-number">0</span> proto kernel scope <span class="hljs-keyword">link</span> src <span class="hljs-number">192.168</span>.<span class="hljs-number">12.107</span> metric <span class="hljs-number">600</span></code></pre><p></p><p>从上面可以看出来,172.17.0.0/16这个网段的数据包可以通过docker0这块网卡发送出去。也就是说,目前宿主机有两个IP,一个是192.168.12.107,用于连接实体的局域网,一个是172.17.0.1,用来和Docker容器通信,从这可以看出宿主机和路由器的作用是一致的。而Docker容器只有一个IP就是172.17.0.2。如果docker容器想要访问外网,那么它就会把数据包发送到网关172.17.0.1,然后由宿主机做NAT发送到192.168.12.1/24这个网段的网关上。<br></p><p>不光宿主机可以ping通容器,而且由于在docker容器中默认路由(网关)是172.17.0.1,所以docker容器不光可以ping主机的172.17.0.1,还能ping通主机的另一个IP:192.168.12.107<br></p><p>此时我们的网络拓扑其实就变成了192.168.12.0/24这个网段里有个宿主机,为了方便理解,我们把这个宿主机看成一个路由器,路由器下面是172.17.0.1/16这个网段。我们把Docker容器看成实实在在的机器设备,连接在宿主机这个路由器的下面。这样Docker的拓扑结构就非常清晰了。我们可以发现这个拓扑结构其实非常的简单。就像家里上网的路由器一样。打个比方:我家里有两个路由器,一个路由器通过PPPOE拨号连接公网,内网地址为192.168.12.1,另一个路由器连接在第一个路由器上面,WAN口IP是192.168.12.107,LAN口地址是172.17.0.1,我们的Docker容器看成一个个的电脑接在第二个路由器LAN上面,所以Docker容器的IP为172.17.0.2。</p><p>第二个路由器(宿主机)通过NAT让我们的电脑们(Docker容器)可以访问互联网。电脑们(Docker容器们)可以互相ping通,也能ping通全部两个路由器。第二个路由器可以ping通电脑们,但是第一个路由器ping不同电脑们。如果还是不理解拓扑结构,可以自己在家里买两个路由器一前一后放上试试。</p><p>网络拓扑图大致如下:</p><p><img src="https://img-blog.csdn.net/20180706103336183?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2x2c2hhb3Jvbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70" alt=""><br></p><p>现在问题来了,如果有一个电脑连接在第一个路由器的下面,和第二个路由器(宿主机)平级,其IP为192.168.12.113,现在它想ping通172.17.0.2这个Docker容器,发现是ping不通的。同样第一台路由器自己也是ping不通Docker容器的</p><p>原因很简单,这台新计算机只能ping通同网段的设备,比如路由器2,因为他们同属于192.168.12.1/24这个网段。而172.17.0.2/16这个网段它并不知道怎么路由过去,只能把目标地址为172.17.0.1/16的数据包发给路由器一,可惜就连第一个路由器也不知道怎么个路由法。所以我们就ping不通了。</p><p>所以现在问题就很好解决了,我们只需要告诉这台新电脑或者第一个路由器到172.17.0.2/16这个网段的路径就可以了。</p><p>于是我们可以在新电脑或者路由器一中这样写<br></p><p></p><pre><code class="language-cs">route <span class="hljs-keyword">add</span> -net <span class="hljs-number">172.17</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/<span class="hljs-number">16</span> gw <span class="hljs-number">192.168</span><span class="hljs-number">.12</span><span class="hljs-number">.107</span></code></pre><br>或者是<p></p><p></p><pre><code class="language-cs">ip route <span class="hljs-keyword">add</span> <span class="hljs-number">172.17</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/<span class="hljs-number">16</span> via <span class="hljs-number">192.168</span><span class="hljs-number">.12</span><span class="hljs-number">.107</span></code></pre><br><p></p><p>普通路由器可以像这样设置</p><p><img src="https://img-blog.csdn.net/20170410173120962?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHZzaGFvcm9uZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" width="600" height="200" alt=""><br></p><p>现在新电脑访问172.17.0.2的数据包就会先被发送到宿主机(第二个路由器)上,然后宿主机再转发到Docker容器上,我们就把Docker容器暴露到局域网里了。</p><p>但此时你会发现你在新计算机上还是ping不通,这是为什么呢。因为路由器二(宿主机)对它的内网机器也就是Docker容器们全部开启了NAT,源IP为172.17.0.2/16的数据包不会出现在宿主机以外的网络中,因为他们被NAT了。这个NAT是Docker进程默认自动帮我们实现的,我们先看一下</p><p></p><pre><code class="language-sql">alex@alex-Lenovo-U310:~$ sudo iptables -t nat -L -n Chain PREROUTING (policy ACCEPT) target prot opt source destination
DOCKER all <span class="hljs-comment">-- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL</span>

Chain INPUT (policy ACCEPT) target prot opt source destination

Chain OUTPUT (policy ACCEPT) target prot opt source destination
DOCKER all <span class="hljs-comment">-- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL</span>

Chain POSTROUTING (policy ACCEPT) target prot opt source destination
MASQUERADE all <span class="hljs-comment">-- 172.17.0.0/16 0.0.0.0/0 </span> MASQUERADE tcp <span class="hljs-comment">-- 172.17.0.2 172.17.0.2 tcp dpt:53</span> MASQUERADE udp <span class="hljs-comment">-- 172.17.0.2 172.17.0.2 udp dpt:53</span>

Chain DOCKER (2 references) target prot opt source destination
RETURN all <span class="hljs-comment">-- 0.0.0.0/0 0.0.0.0/0 </span> DNAT tcp <span class="hljs-comment">-- 0.0.0.0/0 127.0.0.1 tcp dpt:5053 to:172.17.0.2:53</span> DNAT udp <span class="hljs-comment">-- 0.0.0.0/0 127.0.0.1 udp dpt:5053 to:172.17.0.2:53</span> </code></pre><br>注意那句MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0会导致所有172.17.0.0/16的数据包都不能到达docker以外的网络,所以我们要关掉这个NAT,关掉很容易,我们只需删掉这一条iptables规则就可以了。然后源IP为172.17.0.2的数据包就可以出现在192.168.12.1/24的网络中了。<p></p><p></p><pre><code class="language-undefined">sudo iptables -t nat -D POSTROUTING 3</code></pre><br><p></p><p>但是把NAT关掉了以后,虽然内网可以互ping了,但是Docker容器可能上不去网呀。第一个路由器如果自动NAT 了172.17.0.2还好,但要是没有人给Docker容器做NAT,Docker容器就不能上网了,那我们的CDNS也就没法用了。那么如何既保证Docker容器访问外网的数据包被NAT,又保证内网通信不被NAT呢?只要稍微修改一下iptables规则就好了,如下</p><p></p><pre><code class="language-undefined">sudo iptables -t nat -A POSTROUTING -s 172.17.0.2 ! -d 192.168.12.1/24 -j MASQUERADE</code></pre><br>上面的iptables规则通过对内外网流量的分离实现区别的NAT对待,就可以既保证Docker容器正常上网,也可以被内网其他主机访问了。<p></p><p><br></p><p>可能会有这么一种情况,上面所说的第一台路由器不是什么智能路由器,或者你没有权限在那个路由器上配置路由条目,让目标为172.17.0.0/16的数据包通过路由器进行路由。同时你的局域网其他电脑是XP系统的,也没法手动配置路由规则,这该怎么办呢?</p><p>方法一:</p><p>现在以要访问Docker容器的局域网主机为Windows XP系统为例,虽然WinXP不能手动配置路由规则,但是我们可以配置网关,只要我们把网关设置为192.168.12.107也就是我们的宿主机,目标地址为172.17.0.0/16的IP包就会发送到宿主机上,而宿主机不同于第一个路由器,它是知道如何路由这些IP包的。于是我们就可以在WinXP上ping通Docker容器了<br></p><p><img src="https://img-blog.csdn.net/20170410173556933?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHZzaGFvcm9uZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" width="500" height="600" alt=""></p><p><img src="https://img-blog.csdn.net/20170410173616091?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHZzaGFvcm9uZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" width="500" height="500" alt=""><br></p><p>方法二:</p><p>如果你不想修改windows的网关(怕上不去网)可以为windows系统单独设置172.17.0.1/24的目标地址的数据包路由到192.168.12.107,可以使用下面的命令</p><pre><code class="language-css"><span class="hljs-selector-tag">route</span> <span class="hljs-selector-tag">-p</span> <span class="hljs-selector-tag">add</span> 172<span class="hljs-selector-class">.17</span><span class="hljs-selector-class">.0</span><span class="hljs-selector-class">.1</span> <span class="hljs-selector-tag">MASK</span> 255<span class="hljs-selector-class">.255</span><span class="hljs-selector-class">.255</span><span class="hljs-selector-class">.0</span> 192<span class="hljs-selector-class">.168</span><span class="hljs-selector-class">.12</span><span class="hljs-selector-class">.107</span> <span class="hljs-selector-tag">METRIC</span> 3</code></pre><br><p><br></p><p><br></p> </div>

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!