mirror of
https://github.com/yeasy/docker_practice.git
synced 2024-12-26 15:06:18 +00:00
replace '網絡' as '網路'
This commit is contained in:
parent
d24b44076b
commit
893e0f8bb7
@ -1,12 +1,12 @@
|
||||
# 高級網絡配置
|
||||
本章將介紹 Docker 的一些高級網絡配置和選項。
|
||||
# 高級網路配置
|
||||
本章將介紹 Docker 的一些高級網路配置和選項。
|
||||
|
||||
當 Docker 啟動時,會自動在主機上創建一個 `docker0` 虛擬網橋,實際上是 Linux 的一個 bridge,可以理解為一個軟件交換機。它會在掛載到它的網口之間進行轉發。
|
||||
|
||||
同時,Docker 隨機分配一個本地未占用的私有網段(在 [RFC1918](http://tools.ietf.org/html/rfc1918) 中定義)中的一個地址給 `docker0` 接口。比如典型的 `172.17.42.1`,掩碼為 `255.255.0.0`。此後啟動的容器內的網口也會自動分配一個同一網段(`172.17.0.0/16`)的地址。
|
||||
|
||||
當創建一個 Docker 容器的時候,同時會創建了一對 `veth pair` 接口(當數據包發送到一個接口時,另外一個接口也可以收到相同的數據包)。這對接口一端在容器內,即 `eth0`;另一端在本地並被掛載到 `docker0` 網橋,名稱以 `veth` 開頭(例如 `vethAQI2QT`)。通過這種方式,主機可以跟容器通信,容器之間也可以相互通信。Docker 就創建了在主機和所有容器之間一個虛擬共享網絡。
|
||||
當創建一個 Docker 容器的時候,同時會創建了一對 `veth pair` 接口(當數據包發送到一個接口時,另外一個接口也可以收到相同的數據包)。這對接口一端在容器內,即 `eth0`;另一端在本地並被掛載到 `docker0` 網橋,名稱以 `veth` 開頭(例如 `vethAQI2QT`)。通過這種方式,主機可以跟容器通信,容器之間也可以相互通信。Docker 就創建了在主機和所有容器之間一個虛擬共享網路。
|
||||
|
||||
![Docker 網絡](../_images/network.png)
|
||||
![Docker 網路](../_images/network.png)
|
||||
|
||||
接下來的部分將介紹在一些場景中,Docker 所有的網絡定制配置。以及通過 Linux 命令來調整、補充、甚至替換 Docker 默認的網絡配置。
|
||||
接下來的部分將介紹在一些場景中,Docker 所有的網路定制配置。以及通過 Linux 命令來調整、補充、甚至替換 Docker 默認的網路配置。
|
||||
|
@ -1,8 +1,8 @@
|
||||
## 容器訪問控制
|
||||
容器的訪問控制,主要通過 Linux 上的 `iptables` 防火墻來進行管理和實現。`iptables` 是 Linux 上默認的防火墻軟件,在大部分發行版中都自帶。
|
||||
|
||||
### 容器訪問外部網絡
|
||||
容器要想訪問外部網絡,需要本地系統的轉發支持。在Linux 系統中,檢查轉發是否打開。
|
||||
### 容器訪問外部網路
|
||||
容器要想訪問外部網路,需要本地系統的轉發支持。在Linux 系統中,檢查轉發是否打開。
|
||||
|
||||
```
|
||||
$sysctl net.ipv4.ip_forward
|
||||
@ -16,18 +16,18 @@ $sysctl -w net.ipv4.ip_forward=1
|
||||
|
||||
### 容器之間訪問
|
||||
容器之間相互訪問,需要兩方面的支持。
|
||||
* 容器的網絡拓撲是否已經互聯。默認情況下,所有容器都會被連接到 `docker0` 網橋上。
|
||||
* 容器的網路拓撲是否已經互聯。默認情況下,所有容器都會被連接到 `docker0` 網橋上。
|
||||
* 本地系統的防火墻軟件 -- `iptables` 是否允許通過。
|
||||
|
||||
#### 訪問所有端口
|
||||
當啟動 Docker 服務時候,默認會添加一條轉發策略到 iptables 的 FORWARD 鏈上。策略為通過(`ACCEPT`)還是禁止(`DROP`)取決於配置`--icc=true`(缺省值)還是 `--icc=false`。當然,如果手動指定 `--iptables=false` 則不會添加 `iptables` 規則。
|
||||
|
||||
可見,默認情況下,不同容器之間是允許網絡互通的。如果為了安全考慮,可以在 `/etc/default/docker` 文件中配置 `DOCKER_OPTS=--icc=false` 來禁止它。
|
||||
可見,默認情況下,不同容器之間是允許網路互通的。如果為了安全考慮,可以在 `/etc/default/docker` 文件中配置 `DOCKER_OPTS=--icc=false` 來禁止它。
|
||||
|
||||
#### 訪問指定端口
|
||||
在通過 `-icc=false` 關閉網絡訪問後,還可以通過 `--link=CONTAINER_NAME:ALIAS` 選項來訪問容器的開放端口。
|
||||
在通過 `-icc=false` 關閉網路訪問後,還可以通過 `--link=CONTAINER_NAME:ALIAS` 選項來訪問容器的開放端口。
|
||||
|
||||
例如,在啟動 Docker 服務時,可以同時使用 `icc=false --iptables=true` 參數來關閉允許相互的網絡訪問,並讓 Docker 可以修改系統中的 `iptables` 規則。
|
||||
例如,在啟動 Docker 服務時,可以同時使用 `icc=false --iptables=true` 參數來關閉允許相互的網路訪問,並讓 Docker 可以修改系統中的 `iptables` 規則。
|
||||
|
||||
此時,系統中的 `iptables` 規則可能是類似
|
||||
```
|
||||
|
@ -1,4 +1,4 @@
|
||||
## 編輯網絡配置文件
|
||||
## 編輯網路配置文件
|
||||
|
||||
Docker 1.2.0 開始支持在執行中的容器裏編輯 `/etc/hosts`, `/etc/hostname` 和 `/etc/resolve.conf` 文件。
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
## 配置 docker0 網橋
|
||||
Docker 服務默認會創建一個 `docker0` 網橋(其上有一個 `docker0` 內部接口),它在內核層連通了其他的物理或虛擬網卡,這就將所有容器和本地主機都放到同一個物理網絡。
|
||||
Docker 服務默認會創建一個 `docker0` 網橋(其上有一個 `docker0` 內部接口),它在內核層連通了其他的物理或虛擬網卡,這就將所有容器和本地主機都放到同一個物理網路。
|
||||
|
||||
Docker 默認指定了 `docker0` 接口 的 IP 地址和子網掩碼,讓主機和容器之間可以通過網橋相互通信,它還給出了 MTU(接口允許接收的最大傳輸單元),通常是 1500 Bytes,或宿主主機網絡路由上支持的默認值。這些值都可以在服務啟動的時候進行配置。
|
||||
Docker 默認指定了 `docker0` 接口 的 IP 地址和子網掩碼,讓主機和容器之間可以通過網橋相互通信,它還給出了 MTU(接口允許接收的最大傳輸單元),通常是 1500 Bytes,或宿主主機網路路由上支持的默認值。這些值都可以在服務啟動的時候進行配置。
|
||||
* `--bip=CIDR` -- IP 地址加掩碼格式,例如 192.168.1.5/24
|
||||
* `--mtu=BYTES` -- 覆蓋默認的 Docker mtu 配置
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
## 工具和示例
|
||||
在介紹自定義網絡拓撲之前,你可能會對一些外部工具和例子感興趣:
|
||||
在介紹自定義網路拓撲之前,你可能會對一些外部工具和例子感興趣:
|
||||
|
||||
### pipework
|
||||
Jérôme Petazzoni 編寫了一個叫 [pipework](https://github.com/jpetazzo/pipework) 的 shell 腳本,可以幫助用戶在比較復雜的場景中完成容器的連接。
|
||||
|
||||
### playground
|
||||
Brandon Rhodes 創建了一個提供完整的 Docker 容器網絡拓撲管理的 [Python庫](https://github.com/brandon-rhodes/fopnp/tree/m/playground),包括路由、NAT 防火墻;以及一些提供 HTTP, SMTP, POP, IMAP, Telnet, SSH, FTP 的服務器。
|
||||
Brandon Rhodes 創建了一個提供完整的 Docker 容器網路拓撲管理的 [Python庫](https://github.com/brandon-rhodes/fopnp/tree/m/playground),包括路由、NAT 防火墻;以及一些提供 HTTP, SMTP, POP, IMAP, Telnet, SSH, FTP 的服務器。
|
||||
|
@ -1,8 +1,8 @@
|
||||
## 映射容器端口到宿主主機的實現
|
||||
|
||||
默認情況下,容器可以主動訪問到外部網絡的連接,但是外部網絡無法訪問到容器。
|
||||
默認情況下,容器可以主動訪問到外部網路的連接,但是外部網路無法訪問到容器。
|
||||
### 容器訪問外部實現
|
||||
容器所有到外部網絡的連接,源地址都會被NAT成本地系統的IP地址。這是使用 `iptables` 的源地址偽裝操作實現的。
|
||||
容器所有到外部網路的連接,源地址都會被NAT成本地系統的IP地址。這是使用 `iptables` 的源地址偽裝操作實現的。
|
||||
|
||||
查看主機的 NAT 規則。
|
||||
```
|
||||
@ -13,7 +13,7 @@ target prot opt source destination
|
||||
MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16
|
||||
...
|
||||
```
|
||||
其中,上述規則將所有源地址在 `172.17.0.0/16` 網段,目標地址為其他網段(外部網絡)的流量動態偽裝為從系統網卡發出。MASQUERADE 跟傳統 SNAT 的好處是它能動態從網卡獲取地址。
|
||||
其中,上述規則將所有源地址在 `172.17.0.0/16` 網段,目標地址為其他網段(外部網路)的流量動態偽裝為從系統網卡發出。MASQUERADE 跟傳統 SNAT 的好處是它能動態從網卡獲取地址。
|
||||
|
||||
### 外部訪問容器實現
|
||||
|
||||
|
@ -13,7 +13,7 @@ $ sudo docker run -i -t --rm --net=none base /bin/bash
|
||||
root@12e343489d2f:/#
|
||||
```
|
||||
|
||||
找到程序號,然後創建網絡名字空間的跟蹤文件。
|
||||
找到程序號,然後創建網路名字空間的跟蹤文件。
|
||||
```
|
||||
$ sudo docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a
|
||||
2989
|
||||
@ -40,6 +40,6 @@ $ sudo ip netns exec 3004 ip route add 10.1.1.1/32 dev B
|
||||
```
|
||||
現在這 2 個容器就可以相互 ping 通,並成功建立連接。點到點鏈路不需要子網和子網掩碼。
|
||||
|
||||
此外,也可以不指定 `--net=none` 來創建點到點鏈路。這樣容器還可以通過原先的網絡來通信。
|
||||
此外,也可以不指定 `--net=none` 來創建點到點鏈路。這樣容器還可以通過原先的網路來通信。
|
||||
|
||||
利用類似的辦法,可以創建一個只跟主機通信的容器。但是一般情況下,更推薦使用 `--icc=false` 來關閉容器之間的通信。
|
||||
|
@ -1,6 +1,6 @@
|
||||
## 快速配置指南
|
||||
|
||||
下面是一個跟 Docker 網絡相關的命令列表。
|
||||
下面是一個跟 Docker 網路相關的命令列表。
|
||||
|
||||
其中有些命令選項只有在 Docker 服務啟動的時候才能配置,而且不能馬上生效。
|
||||
* `-b BRIDGE or --bridge=BRIDGE` --指定容器掛載的網橋
|
||||
@ -9,7 +9,7 @@
|
||||
* `--icc=true|false` --是否支持容器之間進行通信
|
||||
* `--ip-forward=true|false` --請看下文容器之間的通信
|
||||
* `--iptables=true|false` --禁止 Docker 添加 iptables 規則
|
||||
* `--mtu=BYTES` --容器網絡中的 MTU
|
||||
* `--mtu=BYTES` --容器網路中的 MTU
|
||||
|
||||
下面2個命令選項既可以在啟動服務時指定,也可以 Docker 容器啟動(`docker run`)時候指定。在 Docker 服務啟動的時候指定則會成為默認值,後面執行 `docker run` 時可以覆蓋設置的默認值。
|
||||
* `--dns=IP_ADDRESS...` --使用指定的DNS服務器
|
||||
|
@ -16,7 +16,7 @@
|
||||
在遠端 API 中啟用 CORS 頭。缺省為 false。
|
||||
|
||||
-b=""
|
||||
將容器掛載到一個已存在的網橋上。指定為 'none' 時則禁用容器的網絡。
|
||||
將容器掛載到一個已存在的網橋上。指定為 'none' 時則禁用容器的網路。
|
||||
|
||||
--bip=""
|
||||
讓動態創建的 docker0 采用給定的 CIDR 地址; 與 -b 選項互斥。
|
||||
@ -40,7 +40,7 @@
|
||||
禁止 Docker 添加 iptables 規則。缺省為 true。
|
||||
|
||||
--mtu=VALUE
|
||||
指定容器網絡的 mtu。缺省為 1500。
|
||||
指定容器網路的 mtu。缺省為 1500。
|
||||
|
||||
-p=""
|
||||
指定 daemon 的 PID 文件路徑。缺省為 /var/run/docker.pid。
|
||||
|
@ -1,7 +1,7 @@
|
||||
## [Node.js](https://registry.hub.docker.com/_/node/)
|
||||
|
||||
### 基本信息
|
||||
[Node.js](https://en.wikipedia.org/wiki/Node.js)是基於 JavaScript 的可擴展服務端和網絡軟件開發平臺。
|
||||
[Node.js](https://en.wikipedia.org/wiki/Node.js)是基於 JavaScript 的可擴展服務端和網路軟件開發平臺。
|
||||
該倉庫提供了 Node.js 0.8 ~ 0.11 各個版本的鏡像。
|
||||
|
||||
### 使用方法
|
||||
|
@ -7,7 +7,7 @@
|
||||
最大的公開倉庫是 [Docker Hub](https://hub.docker.com),存放了數量龐大的鏡像供用戶下載。
|
||||
大陸的公開倉庫包括 [Docker Pool](http://www.dockerpool.com) 等,可以提供大陸用戶更穩定快速的訪問。
|
||||
|
||||
當然,用戶也可以在本地網絡內創建一個私有倉庫。
|
||||
當然,用戶也可以在本地網路內創建一個私有倉庫。
|
||||
|
||||
當用戶創建了自己的鏡像之後就可以使用 `push` 命令將它上傳到公有或者私有倉庫,這樣下次在另外一台機器上使用這個鏡像時候,只需要從倉庫上 `pull` 下來就可以了。
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
## 多臺物理主機之間的容器互聯(暴露容器到真實網絡中)
|
||||
## 多臺物理主機之間的容器互聯(暴露容器到真實網路中)
|
||||
Docker 默認的橋接網卡是 docker0。它只會在本機橋接所有的容器網卡,舉例來說容器的虛擬網卡在主機上看一般叫做 veth*** 而 Docker 只是把所有這些網卡橋接在一起,如下:
|
||||
```
|
||||
[root@opnvz ~]# brctl show
|
||||
@ -23,12 +23,12 @@ root@ac6474aeb31d:~# ip a
|
||||
inet6 fe80::487d:68ff:feda:9cf/64 scope link
|
||||
valid_lft forever preferred_lft forever
|
||||
```
|
||||
這樣就可以把這個網絡看成是一個私有的網絡,通過 nat 連接外網,如果要讓外網連接到容器中,就需要做端口映射,即 -p 參數。
|
||||
這樣就可以把這個網路看成是一個私有的網路,通過 nat 連接外網,如果要讓外網連接到容器中,就需要做端口映射,即 -p 參數。
|
||||
|
||||
如果在企業內部應用,或者做多個物理主機的集群,可能需要將多個物理主機的容器組到一個物理網絡中來,那麽就需要將這個網橋橋接到我們指定的網卡上。
|
||||
如果在企業內部應用,或者做多個物理主機的集群,可能需要將多個物理主機的容器組到一個物理網路中來,那麽就需要將這個網橋橋接到我們指定的網卡上。
|
||||
|
||||
### 拓撲圖
|
||||
主機 A 和主機 B 的網卡一都連著物理交換機的同一個 vlan 101,這樣網橋一和網橋三就相當於在同一個物理網絡中了,而容器一、容器三、容器四也在同一物理網絡中了,他們之間可以相互通信,而且可以跟同一 vlan 中的其他物理機器互聯。
|
||||
主機 A 和主機 B 的網卡一都連著物理交換機的同一個 vlan 101,這樣網橋一和網橋三就相當於在同一個物理網路中了,而容器一、容器三、容器四也在同一物理網路中了,他們之間可以相互通信,而且可以跟同一 vlan 中的其他物理機器互聯。
|
||||
![物理拓撲圖](../_images/container_connect_topology.png)
|
||||
|
||||
### ubuntu 示例
|
||||
@ -44,7 +44,7 @@ bridge_ports em1
|
||||
bridge_stp off
|
||||
dns-nameservers 8.8.8.8 192.168.6.1
|
||||
```
|
||||
將 Docker 的默認網橋綁定到這個新建的 br0 上面,這樣就將這臺機器上容器綁定到 em1 這個網卡所對應的物理網絡上了。
|
||||
將 Docker 的默認網橋綁定到這個新建的 br0 上面,這樣就將這臺機器上容器綁定到 em1 這個網卡所對應的物理網路上了。
|
||||
|
||||
ubuntu 修改 /etc/default/docker 文件,添加最後一行內容
|
||||
|
||||
@ -64,7 +64,7 @@ ubuntu 修改 /etc/default/docker 文件,添加最後一行內容
|
||||
DOCKER_OPTS="-b=br0"
|
||||
```
|
||||
|
||||
在啟動 Docker 的時候 使用 -b 參數 將容器綁定到物理網絡上。重啟 Docker 服務後,再進入容器可以看到它已經綁定到你的物理網絡上了。
|
||||
在啟動 Docker 的時候 使用 -b 參數 將容器綁定到物理網路上。重啟 Docker 服務後,再進入容器可以看到它已經綁定到你的物理網路上了。
|
||||
|
||||
```
|
||||
root@ubuntudocker:~# docker ps
|
||||
@ -75,4 +75,4 @@ bridge name bridge id STP enabled interfaces
|
||||
br0 8000.7e6e617c8d53 no em1
|
||||
vethe6e5
|
||||
```
|
||||
這樣就直接把容器暴露到物理網絡上了,多臺物理主機的容器也可以相互聯網了。需要註意的是,這樣就需要自己來保證容器的網絡安全了。
|
||||
這樣就直接把容器暴露到物理網路上了,多臺物理主機的容器也可以相互聯網了。需要註意的是,這樣就需要自己來保證容器的網路安全了。
|
||||
|
@ -1,2 +1,2 @@
|
||||
# Docker 中的網絡功能介紹
|
||||
Docker 允許通過外部訪問容器或容器互聯的方式來提供網絡服務。
|
||||
# Docker 中的網路功能介紹
|
||||
Docker 允許通過外部訪問容器或容器互聯的方式來提供網路服務。
|
||||
|
@ -58,7 +58,7 @@ aed84ee21bde training/webapp:latest python app.py 16 hours ago
|
||||
```
|
||||
可以看到自定義命名的容器,db 和 web,db 容器的 names 列有 db 也有 web/db。這表示 web 容器鏈接到 db 容器,web 容器將被允許訪問 db 容器的信息。
|
||||
|
||||
Docker 在兩個互聯的容器之間創建了一個安全隧道,而且不用映射它們的端口到宿主主機上。在啟動 db 容器的時候並沒有使用 `-p` 和 `-P` 標記,從而避免了暴露數據庫端口到外部網絡上。
|
||||
Docker 在兩個互聯的容器之間創建了一個安全隧道,而且不用映射它們的端口到宿主主機上。在啟動 db 容器的時候並沒有使用 `-p` 和 `-P` 標記,從而避免了暴露數據庫端口到外部網路上。
|
||||
|
||||
Docker 通過 2 種方式為容器公開連接信息:
|
||||
* 環境變量
|
||||
|
@ -1,7 +1,7 @@
|
||||
## 外部訪問容器
|
||||
容器中可以執行一些網絡應用,要讓外部也可以訪問這些應用,可以通過 `-P` 或 `-p` 參數來指定端口映射。
|
||||
容器中可以執行一些網路應用,要讓外部也可以訪問這些應用,可以通過 `-P` 或 `-p` 參數來指定端口映射。
|
||||
|
||||
當使用 -P 標記時,Docker 會隨機映射一個 `49000~49900` 的端口到內部容器開放的網絡端口。
|
||||
當使用 -P 標記時,Docker 會隨機映射一個 `49000~49900` 的端口到內部容器開放的網路端口。
|
||||
|
||||
使用 `docker ps` 可以看到,本地主機的 49155 被映射到了容器的 5000 端口。此時訪問本機的 49115 端口即可訪問容器內 web 應用提供的界面。
|
||||
```
|
||||
@ -48,7 +48,7 @@ $ docker port nostalgic_morse 5000
|
||||
127.0.0.1:49155.
|
||||
```
|
||||
註意:
|
||||
* 容器有自己的內部網絡和 ip 地址(使用 `docker inspect` 可以獲取所有的變量,Docker 還可以有一個可變的網絡配置。)
|
||||
* 容器有自己的內部網路和 ip 地址(使用 `docker inspect` 可以獲取所有的變量,Docker 還可以有一個可變的網路配置。)
|
||||
* -p 標記可以多次使用來綁定多個端口
|
||||
|
||||
例如
|
||||
|
@ -7,12 +7,12 @@
|
||||
|
||||
為了加強對服務端的保護,Docker 的 REST API(客戶端用來跟服務端通信)在 0.5.2 之後使用本地的 Unix 套接字機制替代了原先綁定在 127.0.0.1 上的 TCP 套接字,因為後者容易遭受跨站腳本攻擊。現在用戶使用 Unix 權限檢查來加強套接字的訪問安全。
|
||||
|
||||
用戶仍可以利用 HTTP 提供 REST API 訪問。建議使用安全機制,確保只有可信的網絡或 VPN,或證書保護機制(例如受保護的 stunnel 和 ssl 認證)下的訪問可以進行。此外,還可以使用 HTTPS 和證書來加強保護。
|
||||
用戶仍可以利用 HTTP 提供 REST API 訪問。建議使用安全機制,確保只有可信的網路或 VPN,或證書保護機制(例如受保護的 stunnel 和 ssl 認證)下的訪問可以進行。此外,還可以使用 HTTPS 和證書來加強保護。
|
||||
|
||||
最近改進的 Linux 名字空間機制將可以實現使用非 root 用戶來執行全功能的容器。這將從根本上解決了容器和主機之間共享文件系統而引起的安全問題。
|
||||
|
||||
終極目標是改進 2 個重要的安全特性:
|
||||
* 將容器的 root 用戶映射到本地主機上的非 root 用戶,減輕容器和主機之間因權限提升而引起的安全問題;
|
||||
* 允許 Docker 服務端在非 root 權限下執行,利用安全可靠的子程序來代理執行需要特權權限的操作。這些子程序將只允許在限定範圍內進行操作,例如僅僅負責虛擬網絡設定或文件系統管理、配置操作等。
|
||||
* 允許 Docker 服務端在非 root 權限下執行,利用安全可靠的子程序來代理執行需要特權權限的操作。這些子程序將只允許在限定範圍內進行操作,例如僅僅負責虛擬網路設定或文件系統管理、配置操作等。
|
||||
|
||||
最後,建議采用專用的服務器來執行 Docker 和相關的管理服務(例如管理服務比如 ssh 監控和程序監控、管理工具 nrpe、collectd 等)。其它的業務服務都放到容器中去執行。
|
||||
|
@ -7,12 +7,12 @@ Linux 內核自 2.2 版本起就支持能力機制,它將權限劃分為更加
|
||||
|
||||
默認情況下,Docker 啟動的容器被嚴格限制只允許使用內核的一部分能力。
|
||||
|
||||
使用能力機制對加強 Docker 容器的安全有很多好處。通常,在服務器上會執行一堆需要特權權限的程序,包括有 ssh、cron、syslogd、硬件管理工具模塊(例如負載模塊)、網絡配置工具等等。容器跟這些程序是不同的,因為幾乎所有的特權程序都由容器以外的支持系統來進行管理。
|
||||
使用能力機制對加強 Docker 容器的安全有很多好處。通常,在服務器上會執行一堆需要特權權限的程序,包括有 ssh、cron、syslogd、硬件管理工具模塊(例如負載模塊)、網路配置工具等等。容器跟這些程序是不同的,因為幾乎所有的特權程序都由容器以外的支持系統來進行管理。
|
||||
* ssh 訪問被主機上ssh服務來管理;
|
||||
* cron 通常應該作為用戶程序執行,權限交給使用它服務的應用來處理;
|
||||
* 日誌系統可由 Docker 或第三方服務管理;
|
||||
* 硬件管理無關緊要,容器中也就無需執行 udevd 以及類似服務;
|
||||
* 網絡管理也都在主機上設置,除非特殊需求,容器不需要對網絡進行配置。
|
||||
* 網路管理也都在主機上設置,除非特殊需求,容器不需要對網路進行配置。
|
||||
|
||||
從上面的例子可以看出,大部分情況下,容器並不需要“真正的” root 權限,容器只需要少數的能力即可。為了加強安全,容器可以禁用一些沒必要的權限。
|
||||
* 完全禁止任何 mount 操作;
|
||||
|
@ -3,11 +3,11 @@ Docker 容器和 LXC 容器很相似,所提供的安全特性也差不多。
|
||||
|
||||
名字空間提供了最基礎也是最直接的隔離,在容器中執行的程序不會被執行在主機上的程序和其它容器發現和作用。
|
||||
|
||||
每個容器都有自己獨有的網絡棧,意味著它們不能訪問其他容器的 sockets 或接口。不過,如果主機系統上做了相應的設置,容器可以像跟主機交互一樣的和其他容器交互。當指定公共端口或使用 links 來連接 2 個容器時,容器就可以相互通信了(可以根據配置來限制通信的策略)。
|
||||
每個容器都有自己獨有的網路棧,意味著它們不能訪問其他容器的 sockets 或接口。不過,如果主機系統上做了相應的設置,容器可以像跟主機交互一樣的和其他容器交互。當指定公共端口或使用 links 來連接 2 個容器時,容器就可以相互通信了(可以根據配置來限制通信的策略)。
|
||||
|
||||
從網絡架構的角度來看,所有的容器通過本地主機的網橋接口相互通信,就像物理機器通過物理交換機通信一樣。
|
||||
從網路架構的角度來看,所有的容器通過本地主機的網橋接口相互通信,就像物理機器通過物理交換機通信一樣。
|
||||
|
||||
那麽,內核中實現名字空間和私有網絡的代碼是否足夠成熟?
|
||||
那麽,內核中實現名字空間和私有網路的代碼是否足夠成熟?
|
||||
|
||||
內核名字空間從 2.6.15 版本(2008 年 7 月發布)之後被引入,數年間,這些機制的可靠性在諸多大型生產系統中被實踐驗證。
|
||||
|
||||
|
@ -6,4 +6,4 @@ Docker 當前默認只啟用了能力機制。用戶可以采用多種方案來
|
||||
* 使用一些有增強安全特性的容器模板,比如帶 AppArmor 的模板和 Redhat 帶 SELinux 策略的模板。這些模板提供了額外的安全特性。
|
||||
* 用戶可以自定義訪問控制機制來定制安全策略。
|
||||
|
||||
跟其它添加到 Docker 容器的第三方工具一樣(比如網絡拓撲和文件系統共享),有很多類似的機制,在不改變 Docker 內核情況下就可以加固現有的容器。
|
||||
跟其它添加到 Docker 容器的第三方工具一樣(比如網路拓撲和文件系統共享),有很多類似的機制,在不改變 Docker 內核情況下就可以加固現有的容器。
|
||||
|
@ -6,8 +6,8 @@ Docker 底層的核心技術包括 Linux 上的名字空間(Namespaces)、
|
||||
這種直接的做法實現了對資源最完整的封裝,但很多時候往往意味著系統資源的浪費。
|
||||
例如,以宿主機和虛擬機系統都為 Linux 系統為例,虛擬機中執行的應用其實可以利用宿主機系統中的執行環境。
|
||||
|
||||
我們知道,在作業系統中,包括內核、文件系統、網絡、PID、UID、IPC、內存、硬盤、CPU 等等,所有的資源都是應用程序直接共享的。
|
||||
要想實現虛擬化,除了要實現對內存、CPU、網絡IO、硬盤IO、存儲空間等的限制外,還要實現文件系統、網絡、PID、UID、IPC等等的相互隔離。
|
||||
我們知道,在作業系統中,包括內核、文件系統、網路、PID、UID、IPC、內存、硬盤、CPU 等等,所有的資源都是應用程序直接共享的。
|
||||
要想實現虛擬化,除了要實現對內存、CPU、網路IO、硬盤IO、存儲空間等的限制外,還要實現文件系統、網路、PID、UID、IPC等等的相互隔離。
|
||||
前者相對容易實現一些,後者則需要宿主機系統的深入支持。
|
||||
|
||||
隨著 Linux 系統對於名字空間功能的完善實現,程序員已經可以實現上面的所有需求,讓某些程序在彼此隔離的名字空間中執行。大家雖然都共用一個內核和某些執行時環境(例如一些系統命令和系統庫),但是彼此卻看不到,都以為系統中只有自己的存在。這種機制就是容器(Container),利用名字空間來做權限的隔離控制,利用 cgroups 來做資源分配。
|
||||
|
@ -5,7 +5,7 @@
|
||||
不同用戶的程序就是通過 pid 名字空間隔離開的,且不同名字空間中可以有相同 pid。所有的 LXC 程序在 Docker 中的父程序為Docker程序,每個 LXC 程序具有不同的名字空間。同時由於允許嵌套,因此可以很方便的實現嵌套的 Docker 容器。
|
||||
|
||||
### net 名字空間
|
||||
有了 pid 名字空間, 每個名字空間中的 pid 能夠相互隔離,但是網絡端口還是共享 host 的端口。網絡隔離是通過 net 名字空間實現的, 每個 net 名字空間有獨立的 網絡設備, IP 地址, 路由表, /proc/net 目錄。這樣每個容器的網絡就能隔離開來。Docker 默認采用 veth 的方式,將容器中的虛擬網卡同 host 上的一 個Docker 網橋 docker0 連接在一起。
|
||||
有了 pid 名字空間, 每個名字空間中的 pid 能夠相互隔離,但是網路端口還是共享 host 的端口。網路隔離是通過 net 名字空間實現的, 每個 net 名字空間有獨立的 網路設備, IP 地址, 路由表, /proc/net 目錄。這樣每個容器的網路就能隔離開來。Docker 默認采用 veth 的方式,將容器中的虛擬網卡同 host 上的一 個Docker 網橋 docker0 連接在一起。
|
||||
|
||||
### ipc 名字空間
|
||||
容器中程序交互還是采用了 Linux 常見的程序間交互方法(interprocess communication - IPC), 包括信號量、消息隊列和共享內存等。然而同 VM 不同的是,容器的程序間交互實際上還是 host 上具有相同 pid 名字空間中的程序間交互,因此需要在 IPC 資源申請時加入名字空間信息,每個 IPC 資源有一個唯一的 32 位 id。
|
||||
@ -14,7 +14,7 @@
|
||||
類似 chroot,將一個程序放到一個特定的目錄執行。mnt 名字空間允許不同名字空間的程序看到的文件結構不同,這樣每個名字空間 中的程序所看到的文件目錄就被隔離開了。同 chroot 不同,每個名字空間中的容器在 /proc/mounts 的信息只包含所在名字空間的 mount point。
|
||||
|
||||
### uts 名字空間
|
||||
UTS("UNIX Time-sharing System") 名字空間允許每個容器擁有獨立的 hostname 和 domain name, 使其在網絡上可以被視作一個獨立的節點而非 主機上的一個程序。
|
||||
UTS("UNIX Time-sharing System") 名字空間允許每個容器擁有獨立的 hostname 和 domain name, 使其在網路上可以被視作一個獨立的節點而非 主機上的一個程序。
|
||||
|
||||
### user 名字空間
|
||||
每個容器可以有不同的用戶和組 id, 也就是說可以在容器內用容器內部的用戶執行程序而非主機上的用戶。
|
||||
|
@ -1,39 +1,39 @@
|
||||
## Docker 網絡實現
|
||||
## Docker 網路實現
|
||||
|
||||
Docker 的網絡實現其實就是利用了 Linux 上的網絡名字空間和虛擬網絡設備(特別是 veth pair)。建議先熟悉了解這兩部分的基本概念再閱讀本章。
|
||||
Docker 的網路實現其實就是利用了 Linux 上的網路名字空間和虛擬網路設備(特別是 veth pair)。建議先熟悉了解這兩部分的基本概念再閱讀本章。
|
||||
|
||||
### 基本原理
|
||||
首先,要實現網絡通信,機器需要至少一個網絡接口(物理接口或虛擬接口)來收發數據包;此外,如果不同子網之間要進行通信,需要路由機制。
|
||||
首先,要實現網路通信,機器需要至少一個網路接口(物理接口或虛擬接口)來收發數據包;此外,如果不同子網之間要進行通信,需要路由機制。
|
||||
|
||||
Docker 中的網絡接口默認都是虛擬的接口。虛擬接口的優勢之一是轉發效率較高。
|
||||
Linux 通過在內核中進行數據復制來實現虛擬接口之間的數據轉發,發送接口的發送緩存中的數據包被直接復制到接收接口的接收緩存中。對於本地系統和容器內系統看來就像是一個正常的以太網卡,只是它不需要真正同外部網絡設備通信,速度要快很多。
|
||||
Docker 中的網路接口默認都是虛擬的接口。虛擬接口的優勢之一是轉發效率較高。
|
||||
Linux 通過在內核中進行數據復制來實現虛擬接口之間的數據轉發,發送接口的發送緩存中的數據包被直接復制到接收接口的接收緩存中。對於本地系統和容器內系統看來就像是一個正常的以太網卡,只是它不需要真正同外部網路設備通信,速度要快很多。
|
||||
|
||||
Docker 容器網絡就利用了這項技術。它在本地主機和容器內分別創建一個虛擬接口,並讓它們彼此連通(這樣的一對接口叫做 `veth pair`)。
|
||||
Docker 容器網路就利用了這項技術。它在本地主機和容器內分別創建一個虛擬接口,並讓它們彼此連通(這樣的一對接口叫做 `veth pair`)。
|
||||
|
||||
### 創建網絡參數
|
||||
### 創建網路參數
|
||||
Docker 創建一個容器的時候,會執行如下操作:
|
||||
* 創建一對虛擬接口,分別放到本地主機和新容器中;
|
||||
* 本地主機一端橋接到默認的 docker0 或指定網橋上,並具有一個唯一的名字,如 veth65f9;
|
||||
* 容器一端放到新容器中,並修改名字作為 eth0,這個接口只在容器的名字空間可見;
|
||||
* 從網橋可用地址段中獲取一個空閑地址分配給容器的 eth0,並配置默認路由到橋接網卡 veth65f9。
|
||||
|
||||
完成這些之後,容器就可以使用 eth0 虛擬網卡來連接其他容器和其他網絡。
|
||||
完成這些之後,容器就可以使用 eth0 虛擬網卡來連接其他容器和其他網路。
|
||||
|
||||
可以在 `docker run` 的時候通過 `--net` 參數來指定容器的網絡配置,有4個可選值:
|
||||
可以在 `docker run` 的時候通過 `--net` 參數來指定容器的網路配置,有4個可選值:
|
||||
* `--net=bridge` 這個是默認值,連接到默認的網橋。
|
||||
* `--net=host` 告訴 Docker 不要將容器網絡放到隔離的名字空間中,即不要容器化容器內的網絡。此時容器使用本地主機的網絡,它擁有完全的本地主機接口訪問權限。容器程序可以跟主機其它 root 程序一樣可以打開低範圍的端口,可以訪問本地網絡服務比如 D-bus,還可以讓容器做一些影響整個主機系統的事情,比如重啟主機。因此使用這個選項的時候要非常小心。如果進一步的使用 `--privileged=true`,容器會被允許直接配置主機的網絡堆棧。
|
||||
* `--net=container:NAME_or_ID` 讓 Docker 將新建容器的程序放到一個已存在容器的網絡棧中,新容器程序有自己的文件系統、程序列表和資源限制,但會和已存在的容器共享 IP 地址和端口等網絡資源,兩者程序可以直接通過 `lo` 環回接口通信。
|
||||
* `--net=none` 讓 Docker 將新容器放到隔離的網絡棧中,但是不進行網絡配置。之後,用戶可以自己進行配置。
|
||||
* `--net=host` 告訴 Docker 不要將容器網路放到隔離的名字空間中,即不要容器化容器內的網路。此時容器使用本地主機的網路,它擁有完全的本地主機接口訪問權限。容器程序可以跟主機其它 root 程序一樣可以打開低範圍的端口,可以訪問本地網路服務比如 D-bus,還可以讓容器做一些影響整個主機系統的事情,比如重啟主機。因此使用這個選項的時候要非常小心。如果進一步的使用 `--privileged=true`,容器會被允許直接配置主機的網路堆棧。
|
||||
* `--net=container:NAME_or_ID` 讓 Docker 將新建容器的程序放到一個已存在容器的網路棧中,新容器程序有自己的文件系統、程序列表和資源限制,但會和已存在的容器共享 IP 地址和端口等網路資源,兩者程序可以直接通過 `lo` 環回接口通信。
|
||||
* `--net=none` 讓 Docker 將新容器放到隔離的網路棧中,但是不進行網路配置。之後,用戶可以自己進行配置。
|
||||
|
||||
### 網絡配置細節
|
||||
用戶使用 `--net=none` 後,可以自行配置網絡,讓容器達到跟平常一樣具有訪問網絡的權限。通過這個過程,可以了解 Docker 配置網絡的細節。
|
||||
### 網路配置細節
|
||||
用戶使用 `--net=none` 後,可以自行配置網路,讓容器達到跟平常一樣具有訪問網路的權限。通過這個過程,可以了解 Docker 配置網路的細節。
|
||||
|
||||
首先,啟動一個 `/bin/bash` 容器,指定 `--net=none` 參數。
|
||||
```
|
||||
$ sudo docker run -i -t --rm --net=none base /bin/bash
|
||||
root@63f36fc01b5f:/#
|
||||
```
|
||||
在本地主機查找容器的程序 id,並為它創建網絡命名空間。
|
||||
在本地主機查找容器的程序 id,並為它創建網路命名空間。
|
||||
```
|
||||
$ sudo docker inspect -f '{{.State.Pid}}' 63f36fc01b5f
|
||||
2778
|
||||
@ -54,7 +54,7 @@ $ sudo ip link add A type veth peer name B
|
||||
$ sudo brctl addif docker0 A
|
||||
$ sudo ip link set A up
|
||||
```
|
||||
將B放到容器的網絡命名空間,命名為 eth0,啟動它並配置一個可用 IP(橋接網段)和默認網關。
|
||||
將B放到容器的網路命名空間,命名為 eth0,啟動它並配置一個可用 IP(橋接網段)和默認網關。
|
||||
```
|
||||
$ sudo ip link set B netns $pid
|
||||
$ sudo ip netns exec $pid ip link set dev B name eth0
|
||||
@ -62,8 +62,8 @@ $ sudo ip netns exec $pid ip link set eth0 up
|
||||
$ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0
|
||||
$ sudo ip netns exec $pid ip route add default via 172.17.42.1
|
||||
```
|
||||
以上,就是 Docker 配置網絡的具體過程。
|
||||
以上,就是 Docker 配置網路的具體過程。
|
||||
|
||||
當容器結束後,Docker 會清空容器,容器內的 eth0 會隨網絡命名空間一起被清除,A 接口也被自動從 `docker0` 卸載。
|
||||
當容器結束後,Docker 會清空容器,容器內的 eth0 會隨網路命名空間一起被清除,A 接口也被自動從 `docker0` 卸載。
|
||||
|
||||
此外,用戶可以使用 `ip netns exec` 命令來在指定網絡名字空間中進行配置,從而配置容器內的網絡。
|
||||
此外,用戶可以使用 `ip netns exec` 命令來在指定網路名字空間中進行配置,從而配置容器內的網路。
|
||||
|
Loading…
Reference in New Issue
Block a user