1. 程式人生 > >Docker容器通過獨立IP暴露給區域網的方法

Docker容器通過獨立IP暴露給區域網的方法

Docker容器非常輕量,系統開銷非常少,比VMware或者VirtualBox用起來方便,部署起來也非常容易。官方推薦我們通過埠對映的方式把Docker容器的服務提供給宿主機或者區域網其他容器使用。一般過程是:

1、Docker程序通過監聽宿主機的某個埠,將該埠的資料包傳送給Docker容器

2、宿主機可以開啟防火牆讓區域網其他裝置通過訪問宿主機的埠進而訪問docker的埠

這裡以CDNS為例,CDNS是一個用於避免DNS汙染的程式,通過CDNS可以把你的計算機變成一個抗汙染的DNS伺服器提供給區域網使用。Docker映象下載地址:https://hub.docker.com/r/alexzhuo/cdns/

原理是在Docker容器中啟動CDNS,監聽53埠,Docker容器的IP地址為172.12.0.2,宿主機把5053埠對映到Docker容器上,訪問宿主機的127.0.0.1:5053就相當於訪問Docker的53埠,所以Docker的啟動方法是:

sudo docker run -itd -p 0.0.0.0:5053:53/udp --name=CureDNS alexzhuo/cdns cdns -c /etc/cdns.config.json

這樣我們使用dig工具通過5053埠查詢DNS就是無汙染的DNS了,過程如下:
[email protected]:~$ dig www.facebook.com @127.0.0.1 -p 5053

; DiG 9.10.3-P4-Ubuntu <<>> www.facebook.com @127.0.0.1 -p 5053
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9522
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.facebook.com.		IN	A

;; ANSWER SECTION:
www.facebook.com.	1550	IN	CNAME	star-mini.c10r.facebook.com.
star-mini.c10r.facebook.com. 30	IN	A	31.13.95.36

;; AUTHORITY SECTION:
c10r.facebook.com.	2010	IN	NS	a.ns.c10r.facebook.com.
c10r.facebook.com.	2010	IN	NS	b.ns.c10r.facebook.com.

;; ADDITIONAL SECTION:
a.ns.c10r.facebook.com.	2439	IN	A	69.171.239.11
a.ns.c10r.facebook.com.	2439	IN	AAAA	2a03:2880:fffe:b:face:b00c:0:99
b.ns.c10r.facebook.com.	3351	IN	A	69.171.255.11
b.ns.c10r.facebook.com.	1253	IN	AAAA	2a03:2880:ffff:b:face:b00c:0:99

;; Query time: 47 msec
;; SERVER: 127.0.0.1#5053(127.0.0.1)
;; WHEN: Mon Apr 10 16:21:46 CST 2017
;; MSG SIZE  rcvd: 213

這裡假設我們的宿主機IP是192.168.12.107

如果現在出現另外一臺區域網計算機,IP地址為192.168.12.113,它想把宿主機當成DNS伺服器,那麼我們就需要在192.168.12.113這臺計算機上訪問192.168.12.107:5053來查詢DNS,dig命令如下

dig www.facebook.com @192.168.12.107 -p 5053

這樣做顯然是很不方便的,我們現在希望不經過宿主機這一套NAT和代理,想要直接在區域網內的任意一臺計算機上直接通過IP訪問Docker容器,讓Docker容器完整的暴露在局域網裡而不是僅單單暴露一個53埠。那麼應該如何做呢?

首先通過觀察發現,Docker的預設啟動方式中,會產生一塊虛擬網絡卡,在這裡我們可以理解這塊網絡卡連線著一個虛擬交換機,然後每個Docker容器又會擁有自己單獨的網絡卡和IP,而且所有Docker容器也連線在這個虛擬交換機的下面。我們可以在宿主機上通過ifconfig命令看到這個虛擬網絡卡。

[email protected]:~$ ifconfig
docker0   Link encap:乙太網  硬體地址 02:42:cd:21:5c:81  
          inet 地址:172.17.0.1  廣播:0.0.0.0  掩碼:255.255.0.0
          inet6 地址: fe80::42:cdff:fe21:5c81/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  躍點數:1
          接收資料包:2892 錯誤:0 丟棄:0 過載:0 幀數:0
          傳送資料包:3517 錯誤:0 丟棄:0 過載:0 載波:0
          碰撞:0 傳送佇列長度:0 
          接收位元組:187022 (187.0 KB)  傳送位元組:4771886 (4.7 MB)

lo        Link encap:本地環回  
          inet 地址:127.0.0.1  掩碼:255.0.0.0
          inet6 地址: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  躍點數:1
          接收資料包:9993 錯誤:0 丟棄:0 過載:0 幀數:0
          傳送資料包:9993 錯誤:0 丟棄:0 過載:0 載波:0
          碰撞:0 傳送佇列長度:1 
          接收位元組:934304 (934.3 KB)  傳送位元組:934304 (934.3 KB)

wlp3s0    Link encap:乙太網  硬體地址 74:e5:43:b0:dd:b0  
          inet 地址:192.168.12.107  廣播:192.168.12.255  掩碼:255.255.255.0
          inet6 地址: fe80::8adf:28f7:5ec:3a5d/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  躍點數:1
          接收資料包:69760 錯誤:0 丟棄:0 過載:0 幀數:0
          傳送資料包:64718 錯誤:0 丟棄:0 過載:0 載波:0
          碰撞:0 傳送佇列長度:1000 
          接收位元組:41517057 (41.5 MB)  傳送位元組:9971762 (9.9 MB)

上面的docker0這塊網絡卡就是虛擬網絡卡,它的IP地址是172.17.0.1,它和其他的docker容器都連線在一個虛擬交換機上,網段為172.17.0.0/16,下面我們登入到Docker容器裡面,檢視一下容器的網絡卡和IP
# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:02  
          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:3449 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2811 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:4763490 (4.7 MB)  TX bytes:219998 (219.9 KB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

可以看到這個容器的IP地址為172.17.0.2,現在我們到宿主機裡看看ping 172.17.0.2能不能ping通。

答案當然是能ping通,能ping通的原因就是我們的宿主機裡知道目標地址為172.17.0.1/16的路由資訊,不信我們可以檢視一下

[email protected]:~$ ip route
default via 192.168.12.1 dev wlp3s0  proto static  metric 600 
169.254.0.0/16 dev docker0  scope link  metric 1000 
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1 
192.168.12.0/24 dev wlp3s0  proto kernel  scope link  src 192.168.12.107  metric 600

從上面可以看出來,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這個網段的閘道器上。

不光宿主機可以ping通容器,而且由於在docker容器中預設路由(閘道器)是172.17.0.1,所以docker容器不光可以ping主機的172.17.0.1,還能ping通主機的另一個IP:192.168.12.107

此時我們的網路拓撲其實就變成了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。

第二個路由器(宿主機)通過NAT讓我們的電腦們(Docker容器)可以訪問網際網路。電腦們(Docker容器們)可以互相ping通,也能ping通全部兩個路由器。第二個路由器可以ping通電腦們,但是第一個路由器ping不同電腦們。如果還是不理解拓撲結構,可以自己在家裡買兩個路由器一前一後放上試試。

網路拓撲圖大致如下:


現在問題來了,如果有一個電腦連線在第一個路由器的下面,和第二個路由器(宿主機)平級,其IP為192.168.12.113,現在它想ping通172.17.0.2這個Docker容器,發現是ping不通的。同樣第一臺路由器自己也是ping不通Docker容器的

原因很簡單,這臺新計算機只能ping通同網段的裝置,比如路由器2,因為他們同屬於192.168.12.1/24這個網段。而172.17.0.2/16這個網段它並不知道怎麼路由過去,只能把目標地址為172.17.0.1/16的資料包發給路由器一,可惜就連第一個路由器也不知道怎麼個路由法。所以我們就ping不通了。

所以現在問題就很好解決了,我們只需要告訴這臺新電腦或者第一個路由器到172.17.0.2/16這個網段的路徑就可以了。

於是我們可以在新電腦或者路由器一中這樣寫

route add -net 172.17.0.1/16 gw 192.168.12.107

或者是
ip route add 172.17.0.1/16 via 192.168.12.107

普通路由器可以像這樣設定


現在新電腦訪問172.17.0.2的資料包就會先被髮送到宿主機(第二個路由器)上,然後宿主機再轉發到Docker容器上,我們就把Docker容器暴露到局域網裡了。

但此時你會發現你在新計算機上還是ping不通,這是為什麼呢。因為路由器二(宿主機)對它的內網機器也就是Docker容器們全部開啟了NAT,源IP為172.17.0.2/16的資料包不會出現在宿主機以外的網路中,因為他們被NAT了。這個NAT是Docker程序預設自動幫我們實現的,我們先看一下

[email protected]:~$ sudo iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0           
MASQUERADE  tcp  --  172.17.0.2           172.17.0.2           tcp dpt:53
MASQUERADE  udp  --  172.17.0.2           172.17.0.2           udp dpt:53

Chain DOCKER (2 references)
target     prot opt source               destination         
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
DNAT       tcp  --  0.0.0.0/0            127.0.0.1            tcp dpt:5053 to:172.17.0.2:53
DNAT       udp  --  0.0.0.0/0            127.0.0.1            udp dpt:5053 to:172.17.0.2:53

注意那句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的網路中了。
sudo iptables -t nat -D POSTROUTING 3

但是把NAT關掉了以後,雖然內網可以互ping了,但是Docker容器可能上不去網呀。第一個路由器如果自動NAT 了172.17.0.2還好,但要是沒有人給Docker容器做NAT,Docker容器就不能上網了,那我們的CDNS也就沒法用了。那麼如何既保證Docker容器訪問外網的資料包被NAT,又保證內網通訊不被NAT呢?只要稍微修改一下iptables規則就好了,如下

sudo iptables -t nat -A POSTROUTING -s 172.17.0.2 ! -d 192.168.12.1/24 -j MASQUERADE

上面的iptables規則通過對內外網流量的分離實現區別的NAT對待,就可以既保證Docker容器正常上網,也可以被內網其他主機訪問了。

可能會有這麼一種情況,上面所說的第一臺路由器不是什麼智慧路由器,或者你沒有許可權在那個路由器上配置路由條目,讓目標為172.17.0.0/16的資料包通過路由器進行路由。同時你的區域網其他電腦是XP系統的,也沒法手動配置路由規則,這該怎麼辦呢?

方法一:

現在以要訪問Docker容器的區域網主機為Windows XP系統為例,雖然WinXP不能手動配置路由規則,但是我們可以配置閘道器,只要我們把閘道器設定為192.168.12.107也就是我們的宿主機,目標地址為172.17.0.0/16的IP包就會發送到宿主機上,而宿主機不同於第一個路由器,它是知道如何路由這些IP包的。於是我們就可以在WinXP上ping通Docker容器了


方法二:

如果你不想修改windows的閘道器(怕上不去網)可以為windows系統單獨設定172.17.0.1/24的目標地址的資料包路由到192.168.12.107,可以使用下面的命令

route -p add 172.17.0.1 MASK 255.255.255.0  192.168.12.107 METRIC 3

相關推薦

Docker容器通過獨立IP暴露區域網方法

Docker容器非常輕量,系統開銷非常少,比VMware或者VirtualBox用起來方便,部署起來也非常容易。官方推薦我們通過埠對映的方式把Docker容器的服務提供給宿主機或者區域網其他容器使用。一般過程是:1、Docker程序通過監聽宿主機的某個埠,將該埠的資料包傳送給

Docker容器內網通過獨立IP直接訪問的方法

地址 9.png 自己 圖片 eight borde log margin 宿主機 Docker官方推薦我們通過端口映射的方式把Docker容器的服務提供給宿主機或者局域網其他容器使用。一般過程是: 1、Docker進程通過監聽宿主機的某個端口,將該端口的數據包發送給Doc

用PIPEWORK為docker容器配置獨立IP

官方網站:https://github.com/jpetazzo/pipework 宿主環境:centos7 安裝pipework # wget https://github.com/jpetazzo/pipework/archive/master.zip # unzip master.zip  # cp

Docker容器設定固定IP實現網路聯通(1)——通過Pipework為Docker容器設定

目標 本部落格已經為大家推出了關於Docker的系列內容,相信各位已經對容器產生了濃厚的興趣,但是如果你深入進來可能會發現,容器與虛擬機器的差別還是比較大,特別是在網路方面,還需要很多完善,當然,隨著

Docker容器設定固定IP實現網路聯通(2)——通過Python指令碼實現並解決pipework缺陷

題記 前面已經提到通過使用pipework方式,為容器設定固定IP,但是該方法有一個問題就是如果我們的容器例項重啟,設定的固定IP會丟失,這顯然回事一件令人頭疼的事情,如果我們重啟後IP依然保持設

docker容器通過宿主機ip中轉實現容器之間相互呼叫

一般每個容器,都會對映一個埠到宿主機中,方便在宿主機上訪問,例如ngnix,mysql,redis等等。 但是我們有一種常見的場景,就是a容器,需要通過宿主機的埠對映,呼叫b容器的服務,這裡如果在a容器內部配置localhost/127.0.0.1/0.0.0

Docker容器設定靜態IP

此文已由作者袁歡授權網易雲社群釋出。 歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。 建立docker容器 docker run -it --name=yh -h yh --net=none debian:sshd bash   ### 確保使用--net=none引數,此時新建的容器內不會建

利用pipework為docker容器設定固定IP

      今天介紹如何在redhat/centos7系列機器上使用pipework為docker啟動的容器指定一個固定ip,我們知道預設情況下,docker會使用bridge網路模式為每一個啟動的容器動態分配一個IP,以172.17.0.1為閘道器,172.17.0.2,1

Docker容器設定固定IP實現網路聯通

#!/usr/bin/python # -*- coding:UTF-8 -*- ''' __author__ = 'lioncui' __date__ = '2015-6-16' ''' import docker import os import t

docker容器自定義映象的兩種方法

目錄 1.使用docker commit 使用映象啟動容器,在該容器上修改,在使用命令另存為一個映象 實現思路:使用一個基礎的映象,這個映象可以在centos的官網進行下載,在使用docker進行建立 一個容器,進入到該容器中,刪除原有的yum

使Docker容器擁有可被宿主機以外的機器直接訪問的獨立IP

我們常用的docker容器都是將ip埠對映到宿主機,通過宿主機IP進行訪問。外部無法直接訪問容器IP,下面簡單介紹下怎麼做到區域網內直接訪問docker容器IP。 自動化指令碼見 https://github.com/liwei128

Docker ,Keepalived , 虛擬IP ,NAT,如何把Docker容器裡的虛擬 IP和 埠對映到區域網

機器1                         機器2 192.168.1.100           IP1 :192.168.1.103                                   IP2:172.17.0.1 (Docker bride

【Django】不能通過IP訪問Docker容器裡的Django伺服器

問題描述 建立容器時用-p選項指定了容器開放的埠8000 在Docker容器裡用命令python manage.py runserver啟動了Django伺服器 用docker ps命令得到了

如何定制 Calico 的 IP 池?- 每天5分鐘玩轉 Docker 容器技術(71)

wan mil 討論 mar apple ipam hit initial use 在前面的小節中,我們沒有特別配置,calico 會為自動為網絡分配 subnet,當然我們也可以定制。 首先定義一個 IP Pool,比如: cat <<

通過案例學習 Secret - 每天5分鐘玩轉 Docker 容器技術(110)

docker swarm 教程 容器 在下面的例子中,我們會部署一個 WordPress 應用,WordPress 是流行的開源博客系統。我們將創建一個 MySQL service,將密碼保存到 secret 中。我們還會創建一個 WordPress service,它將使用 secret 連

Docker通過模板創建鏡像,Docker容器、倉庫及數據管理

run 倉庫管理 doc temp 數據卷 blob 客戶端 新建 not 1.通過模板創建鏡像 (1)首先去下載一個模板 http://openvz.org/Download/templates/precreated //下載速度不快,阿銘下載了一個centos6

Service IP 原理 - 每天5分鐘玩轉 Docker 容器技術(137)

Kubernetes Docker 容器 教程 Service Cluster IP 是一個虛擬 IP,是由 Kubernetes 節點上的 iptables 規則管理的。可以通過 iptables-save 命令打印出當前節點的 iptables 規則,因為輸出較多,這裏只截取與 httpd

Tomcat在區域網中localhost可以訪問,但是無法通過本地IP訪問

轉自:https://blog.csdn.net/ybhjx/article/details/73657015 環境:Tomcat6,Windows Server2008 R2, Tomcat使用預設埠8080。 在BO伺服器上使用Tomcat6作為WEB伺服器,在伺服器本地使用http:/

通過java web代理將docker容器配置為jenkins節點

1、安裝centos映象 docker search centos                  //查詢映象 docker pull centos      &nbs

通過Docker容器連線代理Wormhole

Wormhole 是一個能識別名稱空間的由 Socket 啟用的隧道代理。可以讓你安全的連線在不同物理機器上的 Docker 容器。可以用來完成一些有趣的功能,例如連線執行在容器本機的服務或者在連線後建立按需的服務。 連到容器中的 MySQL