網(wǎng)站開發(fā)的英文文獻(xiàn)互聯(lián)網(wǎng)營銷師培訓(xùn)課程
作者主頁: 正函數(shù)的個人主頁
文章收錄專欄: Docker
歡迎大家點贊 👍 收藏 ? 加關(guān)注哦!
高級網(wǎng)絡(luò)配置
注意:本章屬于
Docker
高級配置,如果您是初學(xué)者,您可以暫時跳過本章節(jié),直接學(xué)習(xí) Docker Compose 一節(jié)。
本章將介紹 Docker 的一些高級網(wǎng)絡(luò)配置和選項。
當(dāng) Docker 啟動時,會自動在主機上創(chuàng)建一個 docker0
虛擬網(wǎng)橋,實際上是 Linux 的一個 bridge,可以理解為一個軟件交換機。它會在掛載到它的網(wǎng)口之間進(jìn)行轉(zhuǎn)發(fā)。
同時,Docker 隨機分配一個本地未占用的私有網(wǎng)段(在 RFC1918 中定義)中的一個地址給 docker0
接口。比如典型的 172.17.42.1
,掩碼為 255.255.0.0
。此后啟動的容器內(nèi)的網(wǎng)口也會自動分配一個同一網(wǎng)段(172.17.0.0/16
)的地址。
當(dāng)創(chuàng)建一個 Docker 容器的時候,同時會創(chuàng)建了一對 veth pair
接口(當(dāng)數(shù)據(jù)包發(fā)送到一個接口時,另外一個接口也可以收到相同的數(shù)據(jù)包)。這對接口一端在容器內(nèi),即 eth0
;另一端在本地并被掛載到 docker0
網(wǎng)橋,名稱以 veth
開頭(例如 vethAQI2QT
)。通過這種方式,主機可以跟容器通信,容器之間也可以相互通信。Docker 就創(chuàng)建了在主機和所有容器之間一個虛擬共享網(wǎng)絡(luò)。
接下來的部分將介紹在一些場景中,Docker 所有的網(wǎng)絡(luò)定制配置。以及通過 Linux 命令來調(diào)整、補充、甚至替換 Docker 默認(rèn)的網(wǎng)絡(luò)配置。
一、快速配置指南
下面是一個跟 Docker 網(wǎng)絡(luò)相關(guān)的命令列表。
其中有些命令選項只有在 Docker 服務(wù)啟動的時候才能配置,而且不能馬上生效。
-b BRIDGE
或--bridge=BRIDGE
指定容器掛載的網(wǎng)橋--bip=CIDR
定制 docker0 的掩碼-H SOCKET...
或--host=SOCKET...
Docker 服務(wù)端接收命令的通道--icc=true|false
是否支持容器之間進(jìn)行通信--ip-forward=true|false
請看下文容器之間的通信--iptables=true|false
是否允許 Docker 添加 iptables 規(guī)則--mtu=BYTES
容器網(wǎng)絡(luò)中的 MTU
下面2個命令選項既可以在啟動服務(wù)時指定,也可以在啟動容器時指定。在 Docker 服務(wù)啟動的時候指定則會成為默認(rèn)值,后面執(zhí)行 docker run
時可以覆蓋設(shè)置的默認(rèn)值。
--dns=IP_ADDRESS...
使用指定的DNS服務(wù)器--dns-search=DOMAIN...
指定DNS搜索域
最后這些選項只有在 docker run
執(zhí)行時使用,因為它是針對容器的特性內(nèi)容。
-h HOSTNAME
或--hostname=HOSTNAME
配置容器主機名--link=CONTAINER_NAME:ALIAS
添加到另一個容器的連接--net=bridge|none|container:NAME_or_ID|host
配置容器的橋接模式-p SPEC
或--publish=SPEC
映射容器端口到宿主主機-P or --publish-all=true|false
映射容器所有端口到宿主主機
二、容器訪問控制
容器的訪問控制,主要通過 Linux 上的 iptables
防火墻來進(jìn)行管理和實現(xiàn)。iptables
是 Linux 上默認(rèn)的防火墻軟件,在大部分發(fā)行版中都自帶。
容器訪問外部網(wǎng)絡(luò)
容器要想訪問外部網(wǎng)絡(luò),需要本地系統(tǒng)的轉(zhuǎn)發(fā)支持。在Linux 系統(tǒng)中,檢查轉(zhuǎn)發(fā)是否打開。
$sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
如果為 0,說明沒有開啟轉(zhuǎn)發(fā),則需要手動打開。
$sysctl -w net.ipv4.ip_forward=1
如果在啟動 Docker 服務(wù)的時候設(shè)定 --ip-forward=true
, Docker 就會自動設(shè)定系統(tǒng)的 ip_forward
參數(shù)為 1。
容器之間訪問
容器之間相互訪問,需要兩方面的支持。
- 容器的網(wǎng)絡(luò)拓?fù)涫欠褚呀?jīng)互聯(lián)。默認(rèn)情況下,所有容器都會被連接到
docker0
網(wǎng)橋上。 - 本地系統(tǒng)的防火墻軟件 –
iptables
是否允許通過。
訪問所有端口
當(dāng)啟動 Docker 服務(wù)(即 dockerd)的時候,默認(rèn)會添加一條轉(zhuǎn)發(fā)策略到本地主機 iptables 的 FORWARD 鏈上。策略為通過(ACCEPT
)還是禁止(DROP
)取決于配置--icc=true
(缺省值)還是 --icc=false
。當(dāng)然,如果手動指定 --iptables=false
則不會添加 iptables
規(guī)則。
可見,默認(rèn)情況下,不同容器之間是允許網(wǎng)絡(luò)互通的。如果為了安全考慮,可以在 /etc/docker/daemon.json
文件中配置 {"icc": false}
來禁止它。
訪問指定端口
在通過 -icc=false
關(guān)閉網(wǎng)絡(luò)訪問后,還可以通過 --link=CONTAINER_NAME:ALIAS
選項來訪問容器的開放端口。
例如,在啟動 Docker 服務(wù)時,可以同時使用 icc=false --iptables=true
參數(shù)來關(guān)閉允許相互的網(wǎng)絡(luò)訪問,并讓 Docker 可以修改系統(tǒng)中的 iptables
規(guī)則。
此時,系統(tǒng)中的 iptables
規(guī)則可能是類似
$ sudo iptables -nL
...
Chain FORWARD (policy ACCEPT)
target prot opt source destination
DROP all -- 0.0.0.0/0 0.0.0.0/0
...
之后,啟動容器(docker run
)時使用 --link=CONTAINER_NAME:ALIAS
選項。Docker 會在 iptable
中為 兩個容器分別添加一條 ACCEPT
規(guī)則,允許相互訪問開放的端口(取決于 Dockerfile
中的 EXPOSE
指令)。
當(dāng)添加了 --link=CONTAINER_NAME:ALIAS
選項后,添加了 iptables
規(guī)則。
$ sudo iptables -nL
...
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 172.17.0.2 172.17.0.3 tcp spt:80
ACCEPT tcp -- 172.17.0.3 172.17.0.2 tcp dpt:80
DROP all -- 0.0.0.0/0 0.0.0.0/0
注意:--link=CONTAINER_NAME:ALIAS
中的 CONTAINER_NAME
目前必須是 Docker 分配的名字,或使用 --name
參數(shù)指定的名字。主機名則不會被識別。
三、映射容器端口到宿主主機的實現(xiàn)
默認(rèn)情況下,容器可以主動訪問到外部網(wǎng)絡(luò)的連接,但是外部網(wǎng)絡(luò)無法訪問到容器。
容器訪問外部實現(xiàn)
容器所有到外部網(wǎng)絡(luò)的連接,源地址都會被 NAT 成本地系統(tǒng)的 IP 地址。這是使用 iptables
的源地址偽裝操作實現(xiàn)的。
查看主機的 NAT 規(guī)則。
$ sudo iptables -t nat -nL
...
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16
...
其中,上述規(guī)則將所有源地址在 172.17.0.0/16
網(wǎng)段,目標(biāo)地址為其他網(wǎng)段(外部網(wǎng)絡(luò))的流量動態(tài)偽裝為從系統(tǒng)網(wǎng)卡發(fā)出。MASQUERADE 跟傳統(tǒng) SNAT 的好處是它能動態(tài)從網(wǎng)卡獲取地址。
外部訪問容器實現(xiàn)
容器允許外部訪問,可以在 docker run
時候通過 -p
或 -P
參數(shù)來啟用。
不管用那種辦法,其實也是在本地的 iptable
的 nat 表中添加相應(yīng)的規(guī)則。
使用 -P
時:
$ iptables -t nat -nL
...
Chain DOCKER (2 references)
target prot opt source destination
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49153 to:172.17.0.2:80
使用 -p 80:80
時:
$ iptables -t nat -nL
Chain DOCKER (2 references)
target prot opt source destination
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80
注意:
-
這里的規(guī)則映射了
0.0.0.0
,意味著將接受主機來自所有接口的流量。用戶可以通過-p IP:host_port:container_port
或-p IP::port
來指定允許訪問容器的主機上的 IP、接口等,以制定更嚴(yán)格的規(guī)則。 -
如果希望永久綁定到某個固定的 IP 地址,可以在 Docker 配置文件
/etc/docker/daemon.json
中添加如下內(nèi)容。
{"ip": "0.0.0.0"
}
四、配置 docker0 網(wǎng)橋
Docker 服務(wù)默認(rèn)會創(chuàng)建一個 docker0
網(wǎng)橋(其上有一個 docker0
內(nèi)部接口),它在內(nèi)核層連通了其他的物理或虛擬網(wǎng)卡,這就將所有容器和本地主機都放到同一個物理網(wǎng)絡(luò)。
Docker 默認(rèn)指定了 docker0
接口 的 IP 地址和子網(wǎng)掩碼,讓主機和容器之間可以通過網(wǎng)橋相互通信,它還給出了 MTU(接口允許接收的最大傳輸單元),通常是 1500 Bytes,或宿主主機網(wǎng)絡(luò)路由上支持的默認(rèn)值。這些值都可以在服務(wù)啟動的時候進(jìn)行配置。
--bip=CIDR
IP 地址加掩碼格式,例如 192.168.1.5/24--mtu=BYTES
覆蓋默認(rèn)的 Docker mtu 配置
也可以在配置文件中配置 DOCKER_OPTS,然后重啟服務(wù)。
由于目前 Docker 網(wǎng)橋是 Linux 網(wǎng)橋,用戶可以使用 brctl show
來查看網(wǎng)橋和端口連接信息。
$ sudo brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.3a1d7362b4ee no veth65f9vethdda6
*注:brctl
命令在 Debian、Ubuntu 中可以使用 sudo apt-get install bridge-utils
來安裝。
每次創(chuàng)建一個新容器的時候,Docker 從可用的地址段中選擇一個空閑的 IP 地址分配給容器的 eth0 端口。使用本地主機上 docker0
接口的 IP 作為所有容器的默認(rèn)網(wǎng)關(guān)。
$ sudo docker run -i -t --rm base /bin/bash
$ ip addr show eth0
24: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000link/ether 32:6f:e0:35:57:91 brd ff:ff:ff:ff:ff:ffinet 172.17.0.3/16 scope global eth0valid_lft forever preferred_lft foreverinet6 fe80::306f:e0ff:fe35:5791/64 scope linkvalid_lft forever preferred_lft forever
$ ip route
default via 172.17.42.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3
五、自定義網(wǎng)橋
除了默認(rèn)的 docker0
網(wǎng)橋,用戶也可以指定網(wǎng)橋來連接各個容器。
在啟動 Docker 服務(wù)的時候,使用 -b BRIDGE
或--bridge=BRIDGE
來指定使用的網(wǎng)橋。
如果服務(wù)已經(jīng)運行,那需要先停止服務(wù),并刪除舊的網(wǎng)橋。
$ sudo systemctl stop docker
$ sudo ip link set dev docker0 down
$ sudo brctl delbr docker0
然后創(chuàng)建一個網(wǎng)橋 bridge0
。
$ sudo brctl addbr bridge0
$ sudo ip addr add 192.168.5.1/24 dev bridge0
$ sudo ip link set dev bridge0 up
查看確認(rèn)網(wǎng)橋創(chuàng)建并啟動。
$ ip addr show bridge0
4: bridge0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group defaultlink/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ffinet 192.168.5.1/24 scope global bridge0valid_lft forever preferred_lft forever
在 Docker 配置文件 /etc/docker/daemon.json
中添加如下內(nèi)容,即可將 Docker 默認(rèn)橋接到創(chuàng)建的網(wǎng)橋上。
{"bridge": "bridge0",
}
啟動 Docker 服務(wù)。
新建一個容器,可以看到它已經(jīng)橋接到了 bridge0
上。
可以繼續(xù)用 brctl show
命令查看橋接的信息。另外,在容器中可以使用 ip addr
和 ip route
命令來查看 IP 地址配置和路由信息。
六、工具和示例
在介紹自定義網(wǎng)絡(luò)拓?fù)渲?#xff0c;你可能會對一些外部工具和例子感興趣:
pipework
Jér?me Petazzoni 編寫了一個叫 pipework 的 shell 腳本,可以幫助用戶在比較復(fù)雜的場景中完成容器的連接。
playground
Brandon Rhodes 創(chuàng)建了一個提供完整的 Docker 容器網(wǎng)絡(luò)拓?fù)涔芾淼?Python庫,包括路由、NAT 防火墻;以及一些提供 HTTP
SMTP
POP
IMAP
Telnet
SSH
FTP
的服務(wù)器。
七、編輯網(wǎng)絡(luò)配置文件
Docker 1.2.0 開始支持在運行中的容器里編輯 /etc/hosts
, /etc/hostname
和 /etc/resolv.conf
文件。
但是這些修改是臨時的,只在運行的容器中保留,容器終止或重啟后并不會被保存下來,也不會被 docker commit
提交。
八、配置 HTTP/HTTPS 網(wǎng)絡(luò)代理
使用Docker的過程中,因為網(wǎng)絡(luò)原因,通常需要使用 HTTP/HTTPS 代理來加速鏡像拉取、構(gòu)建和使用。下面是常見的三種場景。
為 dockerd 設(shè)置網(wǎng)絡(luò)代理
“docker pull” 命令是由 dockerd 守護(hù)進(jìn)程執(zhí)行。而 dockerd 守護(hù)進(jìn)程是由 systemd 管理。因此,如果需要在執(zhí)行 “docker pull” 命令時使用 HTTP/HTTPS 代理,需要通過 systemd 配置。
- 為 dockerd 創(chuàng)建配置文件夾。
sudo mkdir -p /etc/systemd/system/docker.service.d
- 為 dockerd 創(chuàng)建 HTTP/HTTPS 網(wǎng)絡(luò)代理的配置文件,文件路徑是 /etc/systemd/system/docker.service.d/http-proxy.conf 。并在該文件中添加相關(guān)環(huán)境變量。
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080/"
Environment="HTTPS_PROXY=http://proxy.example.com:8080/"
Environment="NO_PROXY=localhost,127.0.0.1,.example.com"
- 刷新配置并重啟 docker 服務(wù)。
sudo systemctl daemon-reload
sudo systemctl restart docker
為 docker 容器設(shè)置網(wǎng)絡(luò)代理
在容器運行階段,如果需要使用 HTTP/HTTPS 代理,可以通過更改 docker 客戶端配置,或者指定環(huán)境變量的方式。
- 更改 docker 客戶端配置:創(chuàng)建或更改 ~/.docker/config.json,并在該文件中添加相關(guān)配置。
{"proxies":{"default":{"httpProxy": "http://proxy.example.com:8080/","httpsProxy": "http://proxy.example.com:8080/","noProxy": "localhost,127.0.0.1,.example.com"}}
}
- 指定環(huán)境變量:運行 “docker run” 命令時,指定相關(guān)環(huán)境變量。
環(huán)境變量 | docker run 示例 |
---|---|
HTTP_PROXY | –env HTTP_PROXY=“http://proxy.example.com:8080/” |
HTTPS_PROXY | –env HTTPS_PROXY=“http://proxy.example.com:8080/” |
NO_PROXY | –env NO_PROXY=“l(fā)ocalhost,127.0.0.1,.example.com” |
為 docker build 過程設(shè)置網(wǎng)絡(luò)代理
在容器構(gòu)建階段,如果需要使用 HTTP/HTTPS 代理,可以通過指定 “docker build” 的環(huán)境變量,或者在 Dockerfile 中指定環(huán)境變量的方式。
- 使用 “–build-arg” 指定 “docker build” 的相關(guān)環(huán)境變量
docker build \--build-arg "HTTP_PROXY=http://proxy.example.com:8080/" \--build-arg "HTTPS_PROXY=http://proxy.example.com:8080/" \--build-arg "NO_PROXY=localhost,127.0.0.1,.example.com" .
- 在 Dockerfile 中指定相關(guān)環(huán)境變量
環(huán)境變量 | Dockerfile 示例 |
---|---|
HTTP_PROXY | ENV HTTP_PROXY=“http://proxy.example.com:8080/” |
HTTPS_PROXY | ENV HTTPS_PROXY=“http://proxy.example.com:8080/” |
NO_PROXY | ENV NO_PROXY=“l(fā)ocalhost,127.0.0.1,.example.com” |
八、示例:創(chuàng)建一個點到點連接
默認(rèn)情況下,Docker 會將所有容器連接到由 docker0
提供的虛擬子網(wǎng)中。
用戶有時候需要兩個容器之間可以直連通信,而不用通過主機網(wǎng)橋進(jìn)行橋接。
解決辦法很簡單:創(chuàng)建一對 peer
接口,分別放到兩個容器中,配置成點到點鏈路類型即可。
首先啟動 2 個容器:
$ docker run -i -t --rm --net=none base /bin/bash
root@1f1f4c1f931a:/#
$ docker run -i -t --rm --net=none base /bin/bash
root@12e343489d2f:/#
找到進(jìn)程號,然后創(chuàng)建網(wǎng)絡(luò)命名空間的跟蹤文件。
$ docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a
2989
$ docker inspect -f '{{.State.Pid}}' 12e343489d2f
3004
$ sudo mkdir -p /var/run/netns
$ sudo ln -s /proc/2989/ns/net /var/run/netns/2989
$ sudo ln -s /proc/3004/ns/net /var/run/netns/3004
創(chuàng)建一對 peer
接口,然后配置路由
$ sudo ip link add A type veth peer name B$ sudo ip link set A netns 2989
$ sudo ip netns exec 2989 ip addr add 10.1.1.1/32 dev A
$ sudo ip netns exec 2989 ip link set A up
$ sudo ip netns exec 2989 ip route add 10.1.1.2/32 dev A$ sudo ip link set B netns 3004
$ sudo ip netns exec 3004 ip addr add 10.1.1.2/32 dev B
$ sudo ip netns exec 3004 ip link set B up
$ sudo ip netns exec 3004 ip route add 10.1.1.1/32 dev B
現(xiàn)在這 2 個容器就可以相互 ping 通,并成功建立連接。點到點鏈路不需要子網(wǎng)和子網(wǎng)掩碼。
此外,也可以不指定 --net=none
來創(chuàng)建點到點鏈路。這樣容器還可以通過原先的網(wǎng)絡(luò)來通信。
利用類似的辦法,可以創(chuàng)建一個只跟主機通信的容器。但是一般情況下,更推薦使用 --icc=false
來關(guān)閉容器之間的通信。
作者主頁: 正函數(shù)的個人主頁
文章收錄專欄: Docker
歡迎大家點贊 👍 收藏 ? 加關(guān)注哦!
如果你認(rèn)為這篇文章對你有幫助,請給正函數(shù)點個贊吧,如果發(fā)現(xiàn)什么問題,歡迎評論區(qū)留言!!