Docker啓動會默認創建docker0虛擬網橋,是Linux的一個bridge,可以理解成一個軟件交換機。它會在掛載到它的網口之間進行轉發。
之後所有容器都是在172.17.0.x的網段上,並且可以相互通訊,包括和宿主主機通訊。
當創建一個Docker容器的時候,同時會創建一對veth pair(虛擬設備接口)
(https://www.cnblogs.com/bakari/p/10613710.html)
接口(當數據包發送到一個接口時,另外一個接口也可以收到相同的數據包)。這對接口一端在容器內,即eth0;另一端在本地並被掛載到docker0 網橋,名稱以veth開頭。通過這種方式,主機可以跟容器通信,容器之間也可以相互通信。Docker就創建了在主機和所有容器之間一個虛擬共享網絡。
大概就是書上的這個圖:
一些docker網絡相關的命令列表
-b BRIDGE 或 --bridge=BRIDGE 指定容器掛載的網橋
--bip=CIDR 定製 docker0 的掩碼
-H SOCKET... 或 --host=SOCKET... Docker 服務端接收命令的通道
--icc=true|false 是否支持容器之間進行通信
--iptables=true|false 是否允許 Docker 添加 iptables 規則
--mtu=BYTES 容器網絡中的 MTU(最大傳輸單元)
下面2個命令選項既可以在啓動服務時指定,也可以在啓動容器時指定。在 Docker服務啓動的時候指定則會成爲默認值,後面執行 docker run 時可以覆蓋設置的默認值
--dns=IP_ADDRESS... 使用指定的DNS服務器
--dns-search=DOMAIN... 指定DNS搜索域
最後這些選項只有在 docker run 執行時使用,因爲它是針對容器的特性內容。
-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防火牆來進行管理和實現。
容器想要訪問外部網絡,需要本地系統的轉發支持。在Linux系統中,檢查轉發是否打開。
sysctl net.ipv4.ip_forward
結果net.ipv4.ip_forward = 1中1是打開,如果是0就是沒打開,沒打開則用
sysctl -w net.ipv4.ip_forward=1命令設置成打開。
如果在啓動 Docker 服務的時候設定 --ip-forward=true , Docker 就會自動設定系統的 ip_forward 參數爲 1
容器之間的訪問
容器之間的訪問,需要兩方面的支持。
1.容器的網絡拓撲是否已經互聯。默認情況下,所有容器都會被連接到docker0網橋上。
2.本地系統的防火牆軟件--iptables是否允許通過。
訪問所有端口
當啓動Docker服務(dockerd)的時候,默認會添加一條轉發策略到本地主機iptables的FORWARD鏈上。策略爲通過(ACCEPT)還是禁止(DROP)取決於配置 --icc=true(缺省值)還是--icc=false。如果手動指定--iptables=false則不會添加iptables規則。
所以說在默認情況下,不同容器之間是允許網絡互通的。如果爲了安全考慮,可以在
/etc/docker/daemon.json文件中配置{"icc": false}來禁止。
訪問指定端口
在通過--icc關閉網絡訪問後,可以通過link選項來訪問容器的開放端口。
link=CONTAINER_NAME:ALIAS
例:
在啓動 Docker 服務時,可以同時使用 icc=false --iptables=true 參數來關閉允許相互的網絡訪問,並讓 Docker 可以修改系統中的 iptables 規則。
PS: --link=CONTAINER_NAME:ALIAS 中的 CONTAINER_NAME 目前必須是Docker 分配的名字,或使用 --name 參數指定的名字。主機名則不會被識別。
映射容器端口到宿主主機的實現
默認情況容器可以主動訪問到外部網絡,但是外部網絡無法訪問到容器。
容器訪問外部實現
容器所有到外部網絡的鏈接,源地址都會被NAT成本地系統的IP地址。這是使用iptables的源地址僞裝操作實現的。
查看主機NAT規則sudo iptables -t nat -nL
上面是所有源地址在172.17.0.0/16網段,目標地址是所有0.0.0.0/0,的流量動態僞裝成從系統網卡發出。MASQUERADE 跟傳統 SNAT的好處是它能動態從網卡獲取地址。
外部訪問容器實現
容器允許外部訪問,可以在docker run 時候通過 -p 或 -P 參數來啓用。原理是在本地iptable的net表中添加相應的規則。
比如-p 80:80可能會這樣
上面是所有地址的80都指向了容器裏面的80,如果想鎖定地址可以
-p IP:host_port:container_port 或 -p IP::port
也可以直接配置/etc/docker/daemon.json 中 {"ip": "0.0.0.0"}
配置docker0網橋
Docker服務默認創建docker0 網橋,默認指定了docker0接口的IP地址和子網掩碼,讓主機和容器之間可以通過網橋相互通信,還給出了MTU(接口允許接收的做大傳輸單元),或宿主主機網絡路由上支持的默認值。
--bip=CIDR IP 地址加掩碼格式,例如 192.168.1.5/24
--mtu=BYTES 覆蓋默認的 Docker mtu 配置
也可以在配置文件中配置 DOCKER_OPTS,然後重啓服務。
可以通過brctl show來查看網橋和端口連接信息。
每次創建一個新容器的時候,Docker從可用的地址段中選擇一個空閒的IP地址分配給容器的eth0端口。使用本地主機上docker0接口的IP作爲所有容器的默認網關。
自定義網橋
除了默認的docker0網橋,用戶也可以指定網橋來鏈接各個容器。
啓動docker服務的時候使用 -b BRIDGE 或 --bridge=BRIDGE 來指定使用的網橋。如果服務已經運行,就停掉服務,刪除就網橋。
sudo systemctl stop docker
sudo ip link set dev docker0 down
sudo brctl delbr docker0
然後創建網橋
sudo brctl addbr bridge0
sudo ip addr add 192.168.5.1/24 dev bridge0
sudo ip link set dev bridge0 up
查看確認網橋創建並啓動
ip addr show bridge0
在 Docker 配置文件 /etc/docker/daemon.json 中添加如下內容,即可將Docker 默認橋接到創建的網橋上{"bridge": "bridge0",}
啓動 Docker 服務systemctl start docker
新建一個服務
docker run -d -P training/webapp python app.py
創建一個點到點的連接
默認情況下Docker會將所有容器鏈接到由docker0提供的虛擬子網中。但是有的時候可能需要兩個容器直接通訊,而不是通過主機網橋進行橋接。方法是創建一對peer接口,分別放在兩個容器中,配置成點到點鏈路類型。