一、概述
Docker 網絡從覆寫範圍可分為單個 host 上的容器網絡和跨多個 host 的網絡,本章重點讨論單個host網絡情況。
Docker 安裝時會自動在 host 上建立三個網絡,我們可用 docker network ls 指令檢視:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwATMfRHLGZkRGZkRfJ3bs92YskmNhVTYykVNQJVMRhXVEF1X0hXZ0xCNx8VZ6l2cssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL3YjN1MmNkZGZ4EjN2UGN5cDO2UTY1YzNmhDZjFDM1Q2Y3UTY0Q2LcBTMxIDMy8CXzV2Zh1WavwVbvNmLvR3YxUjLzM3Lc9CX6MHc0RHaiojIsJye.png)
可以使用docker network inspect +NETWORK ID檢視具體資訊
二、網絡
1、none
故名思議,none 網絡就是什麼都沒有的網絡。挂在這個網絡下的容器除了 lo,沒有其他任何網卡。容器建立時,可以通過 --network=none 指定使用 none 網絡。
我們不禁會問,這樣一個封閉的網絡有什麼用呢?
其實還真有應用場景。封閉意味着隔離,一些對安全性要求高并且不需要聯網的應用可以使用 none 網絡。
比如某個容器的唯一用途是生成随機密碼,就可以放到 none 網絡中避免密碼被竊取。
2、host
連接配接到 host 網絡的容器共享 Docker host 的網絡棧,容器的網絡配置與 host 完全一樣。可以通過 --network=host 指定使用 host 網絡。
無法使用-p參數指定端口映射,隻能是容器端口是多少,就占用主控端端口,如果主控端端口已經被占用,容器啟動時報錯
啟動一個容器,映射主控端8080端口
docker run --name tomcat1 -itd -p 8080:8080 tomcat:jdk8
啟動一個容器,網絡使用主控端網路
docker run --name tomcat2 -itd --network=host -P tomcat:jdk8
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
88698a2f1a50 tomcat:jdk8 "catalina.sh run" 7 minutes ago Up 7 minutes tomcat2
e6d991846422 tomcat:jdk8 "catalina.sh run" 8 minutes ago Up 8 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp tomcat1
倆容器都啟動了,但是使用主控端網絡的啟動會報錯
docker logs tomcat2
Caused by: java.net.BindException: Address already in use
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:433)
at sun.nio.ch.Net.bind(Net.java:425)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:220)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:85)
at org.apache.tomcat.util.net.NioEndpoint.initServerSocket(NioEndpoint.java:228)
at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:211)
at org.apache.tomcat.util.net.AbstractEndpoint.bindWithCleanup(AbstractEndpoint.java:1141)
at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:1154)
at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:581)
at org.apache.coyote.http11.AbstractHttp11Protocol.init(AbstractHttp11Protocol.java:74)
at org.apache.catalina.connector.Connector.initInternal(Connector.java:1038)
... 13 more
在容器中可以看到 host 的所有網卡,并且連 hostname 也是 host 的。host 網絡的使用場景又是什麼呢?
直接使用 Docker host 的網絡最大的好處就是性能,如果容器對網絡傳輸效率有較高要求,則可以選擇 host 網絡。當然不便之處就是犧牲一些靈活性,比如要考慮端口沖突問題,Docker host 上已經使用的端口就不能再用了。
Docker host 的另一個用途是讓容器可以直接配置 host 網路。比如某些跨 host 的網絡解決方案,其本身也是以容器方式運作的,這些方案需要對網絡進行配置,比如管理 iptables。
3、bridge
Docker 安裝時會建立一個 命名為 docker0 的 linux bridge,可以通過在配置檔案設定docker0的ip
如果不指定--network,建立的容器預設都會挂到 docker0 上。
docker run --name tomcat1 -itd -p 8080:8080 tomcat:jdk8
docker inspect tomcat1
ifconfig
一個新的網絡接口 veth24d7c68 被挂到了 docker0 上,veth28c57df就是新建立容器的虛拟網卡。
docker exec -it tomcat1 /bin/bash
ip addr
容器有一個網卡eth0@if15。大家可能會問了,為什麼不是veth24d7c68呢?
實際上eth0@if15和veth24d7c68 是一對 veth pair。veth pair是一種成對出現的特殊網絡裝置,可以把它們想象成由一根虛拟網線連接配接起來的一對網卡,網卡的一頭(eth0@if15)在容器中,另一頭(veth24d7c68)挂在網橋 docker0 上,其效果就是将 eth0@if15 也挂在了 docker0 上。
我們還看到 eth0@if15 已經配置了IP 10.10.10.2,為什麼是這個網段呢?讓我們通過 docker network inspect bridge 看一下 bridge 網絡的配置資訊:
原來 bridge 網絡配置的 subnet 就是10.10.10.0/24,并且網關是 10.10.10.1。這個網關在哪兒呢?大概你已經猜出來了,就是 docker0。
容器建立時,docker會自動從10.10.10.0/24中配置設定一個 IP,這裡 24 位的掩碼保證有足夠多的 IP 可以供容器使用
4、自定義
除了 none, host, bridge 這三個自動建立的網絡,使用者也可以根據業務需要建立 user-defined 網絡。
Docker 提供三種 user-defined 網絡驅動:bridge, overlay 和 macvlan。overlay 和 macvlan 用于建立跨主機的網絡。
建立一個網段,-d或者--driver指定驅動類型,--subnet 和 --gateway 參數:
docker network create -d bridge --subnet 172.10.0.0/24 --gateway 172.10.0.1 my_net
docker network ls
這裡我們建立了新的bridge網絡my_net,網段為172.10.0.0/24,網關為172.10.0.1。與前面一樣,網關在 my_net 對應的網橋 br-e6d03a4563b6上:
啟動一個新的容器,使用my_net網絡,指定ip
docker run --name tomcat1 -itd -p 8080:8080 --network=my_net --ip=172.10.0.128 tomcat:jdk8
隻有使用--subnet建立的網絡才能指定靜态 IP。
5、不同網絡通信
之前已經啟動了一個:
再使用預設網絡啟動一個
docker run --name tomcat2 -itd tomcat:jdk8
tomcat1使用的是my_net網絡,tomcat2使用的是bridge網絡,不同網絡之間是互相隔離的,兩者沒法直接通信
為tomcat2添加一塊my_net的網卡
docker network connect my_net tomcat2
docker inspect tomcat2
6、容器間通信
a)IP 通信
IP通信就是直接用IP位址來進行通信,根據上面的分析需要保證兩個容器處于同一個網絡,那麼如果不在同一個網絡如何處理呢?
如果是實體機我們很容易了解,隻需要為其中一台伺服器添加一塊網卡連接配接到另一個網絡就可以了。容器同理,隻需要為其中一個容器添加另外一個容器的網絡就可以了。使用如下指令:
b)Docker DNS Server
通過 IP 通路容器雖然滿足了通信的需求,但還是不夠靈活。因為我們在部署應用之前可能無法确定IP,部署之後再指定要通路的IP會比較麻煩。對于這個問題,可以通過docker自帶的DNS服務解決。
從Docker 1.10 版本開始,docker daemon 實作了一個内嵌的DNS server,使容器可以直接通過“容器名”通信。
方法很簡單,隻要在啟動時用--name為容器命名就可以了。
清理容器
docker rm -f $(docker ps -qa)
使用bridge網絡
docker run --name tomcat1 -itd tomcat:jdk8
docker run --name tomcat2 -itd tomcat:jdk8
[root@docker ~]# docker exec -it tomcat1 sh -c 'ping tomcat2'
ping: tomcat2: Name or service not known
使用my_net網絡
docker run --name tomcat3 -itd --network=my_net tomcat:jdk8
docker run --name tomcat4 -itd --network=my_net tomcat:jdk8
docker exec -it tomcat3 sh -c 'ping tomcat4'
PING tomcat4 (172.10.0.3) 56(84) bytes of data.
64 bytes from tomcat4.my_net (172.10.0.3): icmp_seq=1 ttl=64 time=0.064 ms
64 bytes from tomcat4.my_net (172.10.0.3): icmp_seq=2 ttl=64 time=0.051 ms
64 bytes from tomcat4.my_net (172.10.0.3): icmp_seq=3 ttl=64 time=0.051 ms
使用docker DNS有個限制,隻能在user-defined網絡中使用。預設的bridge網絡是無法使用的。
link參數設定别名
docker run --name centos1 -itd centos:v7.4
docker run --name centos2 --link=centos1:centos1 -itd centos:v7.4
docker exec -it centos2 sh -c 'ping centos1'
使用link預設網絡也可以ping通
c)joined 容器
joined 容器是另一種實作容器間通信的方式。joined 容器非常特别,它可以使兩個或多個容器共享一個網絡棧,共享網卡和配置資訊,joined容器之間可以通過127.0.0.1直接通信。host網絡使得容器與主控端共用同一個網絡,而jointed是使得兩個容器共用同一個網絡。
清理容器
docker rm -f $(docker ps -qa)
docker run --name tomcat1 -itd tomcat:jdk8
docker run --name nginx1 -itd --network=container:tomcat1 nginx:latest
主控端分别curl一下服務
d)容器與外部網絡的連通性
1、容器通路外部網絡