###### tags: `教學` `Docker` `學習筆記` `Dockerfile` # Docker and Container 007 - Network 網路模式 [TOC] --- ## 0. 網路模式 - Network 也是 Docker 的元件。正如其名,它是在管理網路相關設定的指令。 - 使用 Network 建立一個虛擬網路,container 在這個網路裡就可以使用 container name 或 hostname 互相連結。 - 常見四種:none, bridage, container, host - none:容器沒有與任何外界接觸,所以他不能向外連,外面也不能連進去,是一個封閉的網路空間 - briage:我們會把容器在啟動的時候放到某個 bridge network 之中。在這個網路空間中,有所謂的 IP 的概念。 - container:**{TODO}** - host:**{TODO}** ## 1. none模式 - `$ docker network ls`,列出所有網路模式 - `$ docker run -d --network none none-mode alpine tail -f /dev/null` - none-mode,container的名稱 - alpine,使用的image - 修正後可動:`$ docker run -d --net=none alpine tail -f /dev/null` - ![](https://i.imgur.com/PFnvFK3.jpg) - `$ docker network inspect none`,查看none的網路介面,查看相關資料 - ![](https://i.imgur.com/FmWjGIt.jpg) - `$ docker exec -it 30833ebcba10 /bin/sh`,進入none模式下的container裡面,確認網路無法與外界聯繫 - ![](https://i.imgur.com/OltCgno.jpg) --- ## 2. bridge模式 > 預設的網路模式 ### 2.1. 建立一個網路空間 - `$ docker network create --driver bridge my-bridge` - create,建(一個網路空間) - --driver,指定driver - bridge,driver類別為bridge - my-bridge,bridge的網路名稱 - ![](https://i.imgur.com/XUPUT4F.jpg) - `$ docker network inspect my-bridge`,查看none的網路介面,查看相關資料 - ![](https://i.imgur.com/zeGh1hA.jpg) - "Subnet": "172.19.0.0/16" - "Gateway": "172.19.0.1" - `$ docker run -d --network my-bridge bridge-mode001 alpine tail -f /dev/null` - bridge-mode001,container的名稱 - `$ docker network inspect my-bridge`,查看none的網路介面,查看相關資料 - ![](https://i.imgur.com/z80HTVh.jpg) - `$ docker exec -it 8d113ec5c116 /bin/sh`,進到container裡面 - ip addr ls,看有什麼ip ### 2.2. 同時建另一個container - `$ docker run -d --network my-bridge alpine tail -f /dev/null` - `$ docker container rename eager_sinoussi bridge-mode002` - `$ docker network inspect my-bridge`,查看none的網路介面,查看相關資料 - ![](https://i.imgur.com/DgMsjfe.jpg) - ip a,查看所在container的ip - ping 8.8.8.8,確認是否連到外網 - ping 172.19.0.2,確認是否可連到另一個container ### 2.3. 另外建立一個網路空間 - `$ docker network create --driver bridge their-bridge` - `$ docker network inspect their-bridge` - `$ docker run -d --network their-bridge --name bridge-mode003 alpine tail -f /dev/null` - ![](https://i.imgur.com/mKyfBVp.jpg) - `$ docker exec -it 8d113ec5c116 /bin/sh`,進到container裡面 - ip addr ls,看有什麼ip - ping 8.8.8.8,外網 - ping 172.19.0.2,之前的bridge-mode001(這邊會不通) - 不同bridge之間的container是不能互通的 - `$ docker network connect my-bridge bridge-mode003`,把bridge-mode003連結到my-bridge - `$ docker network inspect my-bridge` - ![](https://i.imgur.com/uixe80f.jpg) - 現在bridge-mode003有兩個ip,一個在my-bridge,一個在their-bridge --- ## 3. container模式 - `$ docker container ls` - `$ docker run -d --network container:bridge-mode001 --name container-mode001 alpine tail -f /dev/null,複製一個container` - `$ docker network inspect my-bridge`,查看image的內容 - `$ docker exec -it 10afd27d835d /bin/sh`,進到container裡面,查看ip - 可以發現ip跟複製的container一樣,container模式就是複製特定的網路設定 --- ## 4. host模式 > container不再屬於container,而是當作host(VM linux host) > 讓container的網路世界跟VM linux host一樣 - 修改dockerfile(copy之後的拿掉) ```dockerfile= FROM alpine:latest LABEL name="MyName" ENV myworkdir=/var/www/localhost/htdocs ARG whoami="Sean" WORKDIR ${myworkdir} RUN apk --update add apache2 RUN rm -rf /var/cache/apk/* RUN echo "<h3>I am ${whoami}, this is a test page. line 1st</h3>" >> index.html RUN echo "<h3>I am ${whoami},, this is a test page. line 2nd</h3>" >> index.html RUN echo "<h3>I am ${whoami},, this is a test page. line 3rd</h3>" >> index.html RUN echo "<h3>I am ${whoami},, this is a test page. line 9th</h3>" >> index.html ENTRYPOINT ["httpd", "-D", "FOREGROUND"] ``` - $ `docker build -t kihifung/my-apache .` - $ `docker run -d --network host --name my-apache kihifung/my-apache`, - 這邊就沒有-p(port mapping) - 圖417 - $ `docker exec -it a7a0ebc81647 /bin/sh` - $ `netstat -tulpn`, - ![](https://i.imgur.com/K4gxThU.jpg) --- ##### 參數 * -d|--driver 使用的 driver,預設 bridge,其他參數可以參考[官網](https://docs.docker.com/network/#network-drivers) * --link 連結 container,參數為 container name 或 hostname,也可以設定 alias * --network 指定網路設定 --- ##### 其他指令 - 幫container更名,`$ docker container rename eager_sinoussi bridge-mode002` --- ## troubleshooting ### 摸不到網路 :::warning ``` $ ping 8.8.8.8 connect: Network is unreachable ``` ::: - MAC衝突 :::warning MAC address 18:31:BF:A1:B2:C3 of adapter 'Ethernet0' is within the reserved address range or is.. Adapter 'Ethernet0' may not have network connectivity. ::: ![](https://i.imgur.com/HbGaB8a.png) * [設定方法](https://www.itread01.com/content/1521193139.html) ``` $ ifconfig ens33 down $ cd /etc/sysconfig/network-scripts $ vi ifcfg-ens33 修改其中的"HWADDR=xx:xx:xx:xx:xx:xx"為"MACADDR=xx:xx:xx:xx:xx:xx" $ ifconfig ens33 up $ service network start --- note:HWADDR和MACADDR是有區別的。 1、HWADDR地址其實是網卡的硬挺物理地址,只有廠商才能修改。 2、MACADDR是系統的網卡物理地址,可以用MACADDR來覆蓋HWADDR,但兩這個參數不能同時使用。 而ifconfig命令中顯示的物理地址其實是MACADDR的值,雖然顯示的名稱寫的是HWADDR。所以HWADDR 一般註釋掉,或改為MACADDR ``` --- ## 回顧 ## 課後複習/測驗 ### Q3:容器的網路運作和虛擬機的網路運作有何不同? 面試官提出這樣問題的動機是,點出虛擬機網路與容器網路比較後所帶出的複雜性,對於具備虛擬化技術背景的人來說,了解如何使用Docker容器下的Port來開通服務,以及如何將靜態IP位址分配給容器,能夠區分容器與VM的使用方式是非常重要。表3條列出容器與虛擬機在網路運作方面的差異。 表3 容器與虛擬機網路運作的差異比較 ![](https://lh3.googleusercontent.com/AC8R7UPSsIoATsOwmO4Fe7o1dIAl-gr63IGh0wauA2UwEwhatyLvTlju2fPYVocMnDrlngUzYAxmoYy2Ecul3QRA15RS_f6pVlqnEiHiZ5YcX97Vgde2oYXm-oE4up2gFGbMuExM) --- ### Q15:請列出容器網路運作為何如此重要的原因? 以下是為何需要容器網路的理由: * 容器需要跟外部環境溝通 * 從外部環境連接到容器,進而使用容器所提供的服務。 * 允許容器與Host主機溝通 * 單一主機內或跨主機之間的容器相互連接 * 自動探索容器所提供的服務 * 負載平衡同一服務不同容器的網路流量 * 提供安全的多用戶服務 --- ### Q16:請說明CNM是什麼?它的組成元件有那些? CNM是容器網路模型(Container Network Model)的縮寫,由Docker公司所提出的標準及規範,它構成了Docker環境中容器網路運作的基礎要素,是Docker提供容器網路支持多種網路驅動程式的方法模型,CNM在網路和容器之間提供以下協議: * 相同網段上的所有容器可以相互自由通訊 * 多個網段是分隔容器間流量的方式,所有網路驅動程式皆應支援。 * 讓容器連接到多個網段的方法,是在單一容器上提供多個端點。 * 單一端點加入到網路沙箱中,以便提供網路的可連通性。 如圖4所示,CNM的主要組成元件是: ![](https://lh5.googleusercontent.com/R9KtaTrpqq3p1_Zny-eYSlZIVcAbADNFAi1ohaJH_Yf4ouMzLSzho0Fa3MJ3J26SXI7aAr2kpiwuy2vNpvf4H97lyI869J1l_DsHXbbqbuceuJGGpkmBbvfX2CY9oUZIuzonEKuE) ▲圖4 CNM容器網路模型。 * 網路(Network) * 沙箱(Sandbox) * 端點(Endpoint) 沙箱(Sandbox)只是個通用術語,指的是用來隔離Docker Host主機上網路堆疊的作業系統層之特定技術,Docker在Linux上是使用內核命名空間來提供這沙箱功能,沙箱內的網路「堆疊(Stacks)」,包括網路介面(Interfaces)、路由表和DNS等。CNM術語中的網路是指一個或多個可以通訊的端點,相同網路內的所有端點可以相互通訊,不同網路上的端點在沒有外部繞送的情況下是無法進行溝通(圖5)。 ![](https://lh5.googleusercontent.com/SwJUGjfL7QGYoIKPyKJmAnss4nEJWR4f54_OVLHwVtLmqebNnlmjTbKP4kRT4LUS3HO3bRRGHY-_2vysQcCTpfSdxVVF9j-1xelLTdevO6uJX_5Z0h9HY5N45bKpplCw8J2EdiCl) ▲圖5 中間容器具不同網段的兩個端點。 --- ### Q17:什麼是不同類型的Docker Networking驅動程式? Docker的網路子系統允許插入各種驅動程式使用,預設情況下包含多種驅動程式,用來提供核心網路功能,表4是各種不同的Docker網路驅動程式簡介。 表4 Docker網路驅動程式比較表 ![](https://lh4.googleusercontent.com/yZfArOspNbiLvujm1Fnj_uoSjUXs0H5WchQPgda-3tnbDNT75amHioXku8P5PDUvZ252x7edJCxsPgQM6fWI-VkjKT04XPxAJ_qjRbwFCnPY1ziBMD8Nhp7u2ZyFCax7cXsxHo04) 下面是Docker網路驅動程式的詳細資訊: - Bridge:預設的網路驅動程式,若未指定驅動程式,便會是在容器建立時所用的網路類型。當應用程式在獨立的容器中執行,需要網路通訊時,通常會使用橋接器(Bridge)網路。 - Host:針對單獨容器,移除容器和Docker主機之間的網路隔離,並直接使用Host主機的網路,Swarm服務的Host模式僅適用在Docker 17.06及更高版本。 - Overlay:層疊網路將多個Docker Daemon連接在一起,並讓Swarm服務能夠彼此相互溝通,也可以使用層疊網路來促成叢集服務與獨立容器之間的通訊,或者在不同Docker Daemon上的兩個各自獨立的容器可以進行溝通,此方法無須在這些容器之間執行作業系統層級的路由設定,詳細請參閱官方文件(https://docs.docker.com/network/overlay/)。 - MacVLAN:Macvlan網路允許使用者為容器分配MAC位址(OSI Layer2),使其表現就像網路上的實體設備,Docker Daemon透過其MAC位址將網路封包繞送到容器,當需要直接連接實體網路的高效率低延遲應用情境時,使用macvlan驅動程式可能是最佳選擇,而不再透過Docker主機上網路堆疊來進行NAT路由。 - None:對於此一容器,禁用所有網路功能,通常會在客製化網路驅動程式的情境中使用,none並不適用於Swarm服務。 --- ### Q19:Docker Bridge網路與傳統的Linux橋接器有何不同? 以網路方面術語,橋接器網路是鏈路層(Layer2)設備,它在不同網段間轉發封包流量,網路橋接器可以是硬體設備或是Host主機內核所執行的軟體模擬裝置。 以Docker技術來說,橋接器網路是使用軟體橋接器,此橋接器可以讓連接到同一橋接網路的容器相互通訊,同時提供未連接到此橋接網路之容器的隔離功能,Docker橋接器驅動程式會自動在主機中新增橋接規則,以便讓不同橋接網路上的容器無法直接相互溝通(圖6)。 ![](https://lh3.googleusercontent.com/3ByQ0JOYaOjfrLCb7p1SmfBmT5GPpDHxKz7DqkBQKVzz60nvnmbAD7umqZNLmJCwVf6G8pT-lZogQwyEmETr8_7StE_Bit9JUZBP3Inc_Bi-AmR6a986QhrxrjMTY7NsV2rcDHl6) ▲圖6 Docker Bridge網路示意圖。 --- ### Q20:如何建立使用者定義的Bridge網路? 要建立使用者定義的橋接器網路,可使用docker network create命令,指令範例如圖7所示: ![](https://lh5.googleusercontent.com/7pqE6s9xK1TAH2AFW2zK6BPoXnvYPmcC_GRf64xQ9U4zCQSE04RyAMyeQ37o9c1EkswEem2k8BPXkoQW5B9G1z7G_4ZGoJkxwVxvL_En1LgX79U216yCb1vO-AKtcwlp_F6Lv_Jn) ▲圖7 新增Docker Network。 `$ docker network create mynet`,可以指定子網路、IP位置範圍、閘道器和其他選項,相關詳細訊息,請參閱[docker network create官方文件](https://docs.docker.com/engine/reference/commandline/network_create/)或用「`$ docker network create -help`」指令查詢。 --- ### Q21:如何刪除使用者定義的Bridge網路? 使用docker network rm指令刪除使用者定義的橋接網路(圖8),如果目前已有容器連接到網路,請先將它們斷線: ![](https://lh5.googleusercontent.com/9lsyHz_jDWKSLYcouT_p45aLo9IfZDLmlz1o1ifqOYLuTevXDGY6lDoOEp1Az1hwm7ncBjWnIJpgz_NLpZiC2j6jX-BB_GnrFgIHX9MvD5wiLBqfFmD_46kiekd84b56c0__pDAs) ▲圖8 刪除Docker Network。 `$ docker network rm mynet` --- ### Q22:如何將Docker容器連接到使用者定義的橋接網路? 可以使用以下的指令來進行: `$ docker create --name my-nginx --network my-net --publish 8080:80 nginx:latest` 當建立新容器時,可以指定一個或多個--network參數,此範例將Nginx容器連接到my-net網路,還將容器中的埠號80對應到Docker主機上的埠號8080,因此外部使用者可以存取此連接埠,而其他任何連接到my-net網路的容器都可以存取my-nginx容器上的所有連接埠,當然my-nginx也可存取到其他容器的所有連接埠(圖9)。 ![](https://lh3.googleusercontent.com/87hgAki9eZ29fkSg4LQ5u88fbp6cgW-N-BgQdUvDjFtPnfDjb16X2-HTqAZqYL9SF9bsyArVZfZVvjsX16kX-eVWnJf9mXhWVMgzkBp4NH_E-Ki4tt1SqMsnBfdj8YKK8dp4JN8G) ▲圖9 容器與Host主機的埠號對應。 想將正在執行中的容器連接到現有的使用者定義的橋接網路,請使用docker network connect指令,下列指令將已經在運行的my-nginx容器連接到已存在的my-net網路:  `$ docker network connect my-net my-nginx` --- ### Q23:Docker是否支援IPv6? * 是的,Docker支援IPv6,只有在Linux平台上運行的Docker版本支援IPv6網路,自從Docker Engine 1.5發布以來,皆支援IPv6位址。 * 如要在Docker Daemon程序中啟用IPv6功能,需要編輯「`/etc/docker/daemon.json`」並設置ipv6值為true: `{ "ipv6": true }`,然後重新載入Docker配置檔,重啟Docker:`$ systemctl reload docker`。 * 現在就可以使用--ip6參數來新增網路,並使用--ip6參數來配置容器IPv6位址。 --- ### Q25:層疊網路(Overlay)與橋接網路(Bridge)有何不同? 橋接網路連接兩個網路,讓來自多個通訊網路或網段組成單一合併網路,因此稱為橋接。層疊網路通常用在兩台分隔的主機之間建立虛擬網路,那為何稱為虛擬?因為其網路利用現有網路上所疊架而成的。 **橋接網路適用於單一主機中,而層疊網路則是應用於多台主機上**(圖10)。 ![](https://lh4.googleusercontent.com/VZi1-G2BVhrTTJ1OShCseabu7mYW9drcNl9uacdmuvHRELbxj_FwJzR8cFa81bFzJHTZeuugOsOYhomMwn7qpvwagtbuah61-zUS0SYa-i_vrmRJ3eCPQk5_DfItxrfJPb0Y-e9J) ▲圖10 多台主機以層疊網路連接。 --- ### Q27:如何禁用容器上的網路堆疊? 如果要完全禁用容器中的網路堆疊,可以在啟動容器時使用「--network none」參數,在容器內,就會只新增loopback裝置,圖11為其示意圖。 ![](https://lh6.googleusercontent.com/sMXRSrHuFKXLdFf0Os3BkEIYri1F81U7xbs7ThNO1wdRn8pbEyvIj9G-HO_eEuv5VLTL8_wWyafUT3wFWUUzqmgZvYLe_7heR8kfhXgiNQQMpZlH4cxg4ei7uG8gl710D7ku964_) ▲圖11 無網路容器之拓樸圖。 --- ### Q28:如何替Docker容器建立MacVLAN網路? 要建立Macvlan網路並配合實體網路介面的橋接器,可以使用--driver macvlan和docker network create指令,還需要指定實際運作介面,就是在Docker主機上網路流量會實際通過的網路介面: `$ docker network create -d macvlan --subnet = 172.16.86.0/24 --gateway = 172.16.86.1 -o parent = eth0 collabnet` ### Q29:是否可以排除在MacVLAN網路中已使用的IP位址? 如果需要排除在Macvlan網路中所使用的IP位址,例如當IP位址已經被使用時,請使用--aux-addresses: `$ docker network create -d macvlan –subnet=192.168.32.0/24 –ip-range=192.168.32.128/25 –gateway=192.168.32.254 –aux-address="my-router=192. 168.32.129" -o parent=eth0 collabnet32` MacVLAN相關詳細說明,請參閱[官方文件](https://docs.docker.com/network/macvlan/) --- --- - [回到目錄](https://hackmd.io/@Hualiteq/r1lye3M3d)