作者: Colin Jao 饒康立 – VMware資深技術顧問,主要負責VMware NSX產品線,目前致力於網路虛擬化暨分散式安全防護技術方案的介紹與推廣。

這篇內我們要先和大家簡介在基礎Docker架構下的網路機制,並討論如果衍生到在大型、生產環境內要跑容器架構,只用Docker的基礎網路機制會有哪些面向不容易達成。本篇沒有任何一丁點批評的意味,每個設計都有每個設計的理由。但我們必須要先和大家逐步解釋基礎Docker的網路與安全運作如何進行,K8S的基礎網路與安全架構又是怎麼運作,而在生產環境上可能有哪些點是現有機制不容易做到的;接著當我們和大家討論這些架構內為什麼要包含NSX時,才會有感覺啊,是吧。

我們用下面的示意圖來進行說明:

當我們在一個Linux Docker Host上面跑容器的時候,如果沒有做任何的特別網路設定,此時

  • 這個Linux上會產出一個橋接器 docker0。大家可以想像在這個Linux Host上面有一個虛擬的小交換器,每一個容器都會接到這個docker0橋接器上,進行容器間以及容器與docker host間的網路傳輸。預設狀況下,每一個容器都會拿到一個172.17.0.0/16內的IP地址。每個容器本身的虛擬網卡在Linux內會以veth這個介面開頭為代表
  • Linux kernel本身與這個橋接器的接點則是interface docker 0介面,預設狀況下,這個介面的IP地址會設定為172.17.42.1 /16 (我知道在docker 1.9後的設定不是這樣了,但為了討論方便還是用這個IP來說明)
  • 圖上的int eth0是這個Linux Host對外的IP地址(這IP地址當然是隨實際環境不同的,介面也不見得叫eth0,在某些Linux Distribution可能是像ens160之類的)。而在內部的橋接器與外部的實體網路間,是由Linux Kernel來進行路由與NAT的配置
  • 當內部的Docker container已經部署,要連出去和外部的世界相互溝通時 (outbound traffic),這些連線會透過SNAT (Source Network Address Translation) 的機制,將來源IP由原本的172.17網段,轉換成int eth 0上的實體IP再連出。因此,Docker Host內的container IP在外部實體網路內是看不到的
  • 同樣的,如果這些容器提供各項微服務如網頁、認證、UI、轉碼功能給外部的用戶使用時 (inbound traffic),外部的用戶因為看不到內部172.17的IP,此時同樣需要利用DNAT (Destination Network Address Translation) 的機制。比如說當我們執行 # docker run -p 8080:80時,就能把一個內部跑網頁80 port服務的容器,在外部能夠以eth0 IP上的8080 port來進行連接。而如果我們內部有多個docker容器都提供80 port的服務,在這個docker host上就必須以不同的服務埠來分別了(比如說8080是對應第一個容器,8081是對應第二個容器…以此類推)
  • 每一個容器前都有iptable防火牆進行保護。而整個docker 0上的網路封包要進出docker host時,也有iptable防火牆來防護。所以其實在Docker Host上,先不管好不好維運,對應到東西向的封包 (container <–> container) 或是南北向的封包 (container <–> physical) 都是有辦法進行防護的。

好,如果大家一下看不懂上面我寫什麼,但是對VMware很了解的話,想像一下:把Docker Host比擬成你筆電上的VMware Workstation,container比擬成Workstation內的虛機。docker0橋接器就像是Workstation內的VMnet8虛擬交換器。當管理者選擇虛機要採用NAT模式時,Workstation會建立一個192.168.X.0/24的內部網路(對比 172.17.0.0/16) 讓虛機接上。虛機會透過SNAT的方式透過Workstation連到外面環境,而反過來如果虛機要提供服務,管理者會設定Port Forwarding (DNAT) 來透過特定Port讓外部機器可連到內部虛機。

到目前可以嗎?接著問一個問題:在一台Workstation上大家玩得很開心,但如果你有兩台VMware Workstation,虛機都採用NAT模式,你要怎麼讓兩台不同Workstation上的兩台虛機互連?同理,在Docker的預設網路設定內,在單個Docker Host內沒有太多問題,但當環境一大,有兩個以上的Docker Host,此時

  • 想像你的某個web微服務有10個容器,五個在Host 1另外五個在Host 2。外面的用戶或是Load Balancer要怎麼連到這十個容器?Host 1的8080~8084 Port再加上Host 2的8080~8084 Port嗎?有沒有覺得很難維護?如果這個服務有一百個容器呢?
  • 想像你的SaaS應用內,負責UI的微服務容器在Host 1上,AP-Logic的微服務容器在Host 2上,請問UI container要如何連到AP-Logic container?回答這個問題前請想清楚喔,這是兩組都躲在NAT後面,而且本地IP網段一模一樣 (172.17.0.0/16),位址也有機會一模一樣的容器喔
  • 你的資安Team因為合規與稽核需求,要求UI的容器與AP-logic的容器間要有防火牆防護。你打算怎麼做,成為iptables高手嗎?而且請把上面的情境連帶想像一下,iptables內除了防火牆也會有NAT喔,你防火牆規則內的來源與目的地IP地址會是哪一個?
  • 業務Team要求進行應用的scale-out / scale-in,如前篇所講,這本來就是SaaS App該做的事。但你在要擴充新的container或移除現有的container時,上面的網路連接 / NAT / 防火牆怎麼辦?

我知道大家可能會想說可以這樣做或那樣改,像是配置–net=host,或是改成libnetwork等等的啊。但事實上,生產環境內沒有人希望用這種單機版的做法。就像在各位的機房內,不會把虛機放在Workstation或是單台vSphere ESXi上提供服務,你會建立一個vCenter / 多台vSphere的環境來集中管理。同樣的,Docker具備強大的容器功能,但我們會需要一個能管理、維護、配置大型環境的機制,這就是CaaS (Container as a Service) 相關方案如Kubernetes / Docker Swarm / Fleet / Mesos等等要出場的原因了。在下一篇內,我們要和大家討論在Kubernetes上的網路及安全運作機制。