###### 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`
- 
- `$ docker network inspect none`,查看none的網路介面,查看相關資料
- 
- `$ docker exec -it 30833ebcba10 /bin/sh`,進入none模式下的container裡面,確認網路無法與外界聯繫
- 
---
## 2. bridge模式
> 預設的網路模式
### 2.1. 建立一個網路空間
- `$ docker network create --driver bridge my-bridge`
- create,建(一個網路空間)
- --driver,指定driver
- bridge,driver類別為bridge
- my-bridge,bridge的網路名稱
- 
- `$ docker network inspect my-bridge`,查看none的網路介面,查看相關資料
- 
- "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的網路介面,查看相關資料
- 
- `$ 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的網路介面,查看相關資料
- 
- 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`
- 
- `$ 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`
- 
- 現在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`,
- 
---
##### 參數
* -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://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 容器與虛擬機網路運作的差異比較

---
### Q15:請列出容器網路運作為何如此重要的原因?
以下是為何需要容器網路的理由:
* 容器需要跟外部環境溝通
* 從外部環境連接到容器,進而使用容器所提供的服務。
* 允許容器與Host主機溝通
* 單一主機內或跨主機之間的容器相互連接
* 自動探索容器所提供的服務
* 負載平衡同一服務不同容器的網路流量
* 提供安全的多用戶服務
---
### Q16:請說明CNM是什麼?它的組成元件有那些?
CNM是容器網路模型(Container Network Model)的縮寫,由Docker公司所提出的標準及規範,它構成了Docker環境中容器網路運作的基礎要素,是Docker提供容器網路支持多種網路驅動程式的方法模型,CNM在網路和容器之間提供以下協議:
* 相同網段上的所有容器可以相互自由通訊
* 多個網段是分隔容器間流量的方式,所有網路驅動程式皆應支援。
* 讓容器連接到多個網段的方法,是在單一容器上提供多個端點。
* 單一端點加入到網路沙箱中,以便提供網路的可連通性。
如圖4所示,CNM的主要組成元件是:

▲圖4 CNM容器網路模型。
* 網路(Network)
* 沙箱(Sandbox)
* 端點(Endpoint)
沙箱(Sandbox)只是個通用術語,指的是用來隔離Docker Host主機上網路堆疊的作業系統層之特定技術,Docker在Linux上是使用內核命名空間來提供這沙箱功能,沙箱內的網路「堆疊(Stacks)」,包括網路介面(Interfaces)、路由表和DNS等。CNM術語中的網路是指一個或多個可以通訊的端點,相同網路內的所有端點可以相互通訊,不同網路上的端點在沒有外部繞送的情況下是無法進行溝通(圖5)。

▲圖5 中間容器具不同網段的兩個端點。
---
### Q17:什麼是不同類型的Docker Networking驅動程式?
Docker的網路子系統允許插入各種驅動程式使用,預設情況下包含多種驅動程式,用來提供核心網路功能,表4是各種不同的Docker網路驅動程式簡介。
表4 Docker網路驅動程式比較表

下面是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)。

▲圖6 Docker Bridge網路示意圖。
---
### Q20:如何建立使用者定義的Bridge網路?
要建立使用者定義的橋接器網路,可使用docker network create命令,指令範例如圖7所示:

▲圖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),如果目前已有容器連接到網路,請先將它們斷線:

▲圖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)。

▲圖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)。

▲圖10 多台主機以層疊網路連接。
---
### Q27:如何禁用容器上的網路堆疊?
如果要完全禁用容器中的網路堆疊,可以在啟動容器時使用「--network none」參數,在容器內,就會只新增loopback裝置,圖11為其示意圖。

▲圖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)