Docker網路
一、什麼是ip地址
通常我們看到的ip地址會長這樣(由點分割的十進位數):192.168.1.1
其實ip地址是一個32位的二進位數,被分割成4部分,每部分8位。也就是說他們其實長成這樣
00000000.00000000.00000000.00000000
每一部分都是8位的二進位數,那他能表示的範圍其實就是0~255,並且在一個子網中,第一個0為保留位,最後一個255為廣播位,這兩位不會劃分出去。(比如在區域網中找不到一個完全匹配的ip時,可能就會廣播數據報文,廣播的地址就會使用255)
所以說,一般情況下,區域網中可以使用的ip為1~254
0.0.0.0 迴環地址
255.255.255.255 廣播地址
二、劃分子網
2.1、為什麼要劃分子網
劃分子網是為了更好的利用ip地址資源,因為ip地址就是上面提到的4個byte位元組組成的,一共就有2的32方個,隨著互聯網的發展,ip地址已經不夠用了
現在的解決方案有兩種,一種是將ipv4升級成ipv6,第二種就是現在說的劃分子網,通過合理劃分子網來緩解ip地址枯竭的問題。
2.2、子網分類
子網分類說的是人為的將子網分成A、B、C、D類,每個分類都有兩部分組成:網路號+主機號
無論怎麼劃分,網路號和主機號一共32位是不會變的
A類:8位網路號 24位主機號
B類:16位網路號 16位主機號
C類:24位網路號 8位主機號
2.3、子網劃分
子網劃分的應用場景:
上面C類子網支援254台主機,B類子網支援6萬多台主機。
那假設現在有一個公司,他們公司有幾千名員工,如果為他們申請ip的話請問是該申請C類地址還是B類地址呢?
很顯然,C類肯定不夠用,B類又會浪費掉好幾萬個ip資源~
這時就得進行子網劃分,拿這個例子來說就是我們給該公司申請一個B類地址,然後將B類地址中的部分主機位當作網路ID,這樣的話,主機位數就變少了,最新的網路號 = 網路號+從主機位劃分出來的網路ID,原來的二級Ip 地址被劃分成三級Ip地址,收益就是:實現節省ip地址。
實戰子網劃分
假設我們對192.168.1.0這個網路號進行子網劃分。
然後我們從主機號借用兩位當作網路號
# 如果不進行子網分,它是一個C類網路地址,可以承載254台機器
192.168.1.00000000
# 借兩位主機位當作網路id來 劃分子網,可以得到下面四個子網
192.168.1.00 000000
192.168.1.01 000000
192.168.1.10 000000
192.168.1.11 000000
網路號相同的ip視為在一個區域網中,這樣就將原來的一個C類地址劃分成四個網路地址,也就能給四個公司使用,而且每個網路中都能分配2的6次方個左右的ip地址。
一個設備有多個ip是正常的,它有多個網卡,就能有多個公網ip,相應的每個設備也有私網ip,也就是他所在的區域網中的ip(一般是通過DHCP獲取的)
想接入互聯網就的有公網ip,全球有42億的ipv4的公網ip,我們的硬體設備默認有一個自己的本地ip,比如192.168…, 當設備連通區域網後,設備的本地ip其實是這個公網ip下的區域網的ip地址之一,這樣可以盡最大可能的利用有限的ip網路地址資源(而不用為每一台設備都分配一個獨有的公網ip)
2.4、子網掩碼
在上一個例子中我們將這個網路號192.168.1.0,通過子網劃分,分成了四個網路,如下
192.168.1.00 000000
192.168.1.01 000000
192.168.1.10 000000
192.168.1.11 000000
問題是怎麼讓機器區分開這是四個網路地址,而不是一個C類地址呢?
這就引出了子網掩碼的概念: 子網掩碼和ip地址同為32位,子網掩碼為1的區域對應著ip地址的網路號部分,子網掩碼為0的區域對應著ip地址的主機號部分。
就這個例子來說,它的子網掩碼如下
# 192.168.1.0 ==轉二進位==> 11000000.10101000.00000001.00000000
# 本來他是C類網路地址:它的網路號為前24位,後8位為主機號
# 然後我們劃分子網,從主機位給網路位借兩位,也就是前26位是網路號,後6位是主機號
# 對應的子網掩碼位:前26位為1,後6位為0。即11111111.11111111.11111111.11000000
# 11111111.11111111.11111111.11000000 =轉十進位=>255.255.255.192
如果通過ip和子網掩碼得出網路ID呢?
# 兩者的二進位表示做與運算
# 相同為1,不同為0
網路ID相同,說明這兩個ip在同一個局域子網中
2.5、無分類-構成超網
這裡說的無分類-構成超網本質上也是一種ip地址的編址方式,並且它消除了傳統的ABCD這種劃分子網的概念。
它的編製方式為:網路號/主機號
通常使用這種方式編址的ip長這個樣子:192.68.1.1/20
在ipv4中,ip地址的總長度為32位這是不會變的,這裡的20表示的是在這總長為32位的地址中,前20為網路號,剩下的12位是主機號
三、網路模式
常見的網路模式有:橋接模式、NAT模式、僅主機模式。比如在vmware中設置虛擬機的網路模式時,可以看到
3.1、橋接
橋接模式的本質是:使用一個虛擬的交換機,將虛擬機和物理機網卡打通。他們同屬於一個網段
在這種模式下:有如下特性:
- 虛擬機和物理機同屬一個網段
- 虛擬機之間可以相同Ping通
- 虛擬機和物理機之間可以相互ping通
- 只要主機能上網,虛擬機就能上網
3.2、NAT
NAT是一種網路地址轉換技術,實現了區域網內的使用自己的本地IP即可聯通互聯網(NAT會將本地Ip,轉換成全球IP)
常見的你家裡的wifi,家裡按了網線之後會有一個公網ip,但是家裡的任何智慧設備通過路由器連接上wifi後都能同時上網,因為路由器會分配給設備一個區域網ip,設備使用這個區域網ip上網,其中的轉換技術就是NAT技術
有如下特性:
- 主機能上網,虛擬機就能上網
- 虛擬機直接可以互通
3.3、Host
Host,僅主機,即它是存在於主機內部的一個虛擬網路。
這僅主機模式下,有一塊虛擬網卡,這塊網卡的網段和主機上物理網卡的網段是不相同的。
所有的虛擬機在虛擬網卡的網段下,所以他們彼此直接互通。
默認情況下,虛擬機可以訪問到物理機,但是默認情況下虛擬機不能上網的。(也可以通過修改配置讓他們上互聯網)
3.4、內部網路
在內部網路下,虛擬機和外部完全隔斷,只允許虛擬機之間才能相互訪問
四、Docker0
Docker網路的核心是Docker0
通過ip addr
可以看到伺服器中如下幾塊網卡
查看公網ip可以在控制台獲取或者執行:curl cip.cc
4.1、小實驗1:
Docker中啟動Nginx容器,問宿主機能通過容器的ip地址ping通它嗎?
# 運行鏡像
[root@VM-0-15-centos ~]# docker run -d -P --name nginx1 nginx
# 檢查容器是否運行起來了
[root@VM-0-15-centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
962cf239325d nginx "/docker-entrypoint.…" 5 seconds ago Up 3 seconds 0.0.0.0:32768->80/tcp nginx1
# 進入容器中
[root@VM-0-15-centos ~]# docker exec -it nginx1 /bin/bash
# 查看容器ip地址
root@962cf239325d:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 962cf239325d
# 退出容器
root@962cf239325d:/# exit
exit
# ping
[root@VM-0-15-centos ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.064 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.056 ms
c64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.058 ms
實驗結果很明顯:可以ping通!
為什麼能ping通呢???
查看容器和宿主機網卡的資訊就知道了
宿主機中有一塊叫Docker0的網卡如下,它的網路段172.17.0.1/16
容器的網卡資訊如下:
可以看到這宿主機和容器其實是在同一個網段的~,所以肯定能通!
4.2、小實驗2:
如果我宿主機上的容器中同時運行兩個容器,問:
這兩個容器之間能通過彼此的ip的相互ping通嗎?
# 檢查兩個容器是否都運行起來了
[root@VM-0-15-centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d37b518465a0 tomcat "catalina.sh run" 2 seconds ago Up 2 seconds 0.0.0.0:32772->8080/tcp tomcat2
85859d226c8c f796d3d2c195 "catalina.sh run" 17 minutes ago Up 17 minutes 0.0.0.0:32771->8080/tcp tomcat1
# 查看記錄tomcat1的ip
[root@VM-0-15-centos ~]# docker exec -it tomcat1 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
184: eth0@if185: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 查看記錄tomcat2的ip
[root@VM-0-15-centos ~]# docker exec -it tomcat2 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
186: eth0@if187: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 使用tomcat2 ping tomcat1
[root@VM-0-15-centos ~]# docker exec -it tomcat2 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.089 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.066 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.072 ms
^C
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.066/0.075/0.089/0.014 ms
# 使用tomcat1 ping tomcat2
[root@VM-0-15-centos ~]# docker exec -it tomcat1 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.069 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.061 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.070 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.070 ms
^C
結論很明顯:彼此之間能ping通!
那Docker是怎麼做的呢?
我們安裝Docker後會帶有一個默認的網卡叫做Docker0,它實際上是一個網橋,其中有一端連接在真實的互聯網上,使用的的技術是veth-pair橋接技術
此時我的Docker中已經運行了兩個容器了,現在去看下宿主機和兩個容器的網卡資訊。
宿主機:
tomcat1:
tomcat2:
仔細看如上兩圖中多出來的網卡命名對應關係
# 宿主機多出來的: 185: veth79ccfd1@if184
# 對應容器tomcat1: 184: eth0@if185
# 宿主機多出來的: 187: vethac83886@if186
# 對應容器tomcat2: 186: eth0@if187
這種網卡成對對應的關係,就是藉助veth-pair技術實現的
veth-pair就是一對虛擬的網路介面,成對出現,一端連著協議,一端彼此相連。由它充當一個橋樑的作用,連接各個Docker 容器,實現網路數據交互
在當前的案例中之間能Ping的
在不指定容器網路的情況下,默認容器使用的Docker0做網橋
通過下面的命令查看使用Docker0的所有Container
Docker會為容器分配一個可用的ip
分配的ip都在上圖規定的subnet子網網段下的格式:172.17.0.2/16
在上面劃分子網時有提到這種劃分的方式,最後的16為它的網路號,也就是說他還有16位的機器號,也就是2的16次方-2個
五、Docker網路 –link
前面的驗證了Docker兩個不同的容器可以通過ip直接ping通
–link 可以讓我們讓兩個容器通過服務名直接ping通
# 使用--link這個啟動參數,連通不同的容器,實現通過服務名就ping通容器
[root@VM-0-15-centos ~]# docker run -d -P --name tomcat3 --link tomcat2 tomcat
2d8c1363094cd2e09bcd3d3a4e85e0864f32718d38aa4dab9640522c4ea3a87a
# 檢查容器是否正常啟動了
[root@VM-0-15-centos ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2d8c1363094c tomcat "catalina.sh run" 2 seconds ago Up 2 seconds 0.0.0.0:32773->8080/tcp tomcat3
d37b518465a0 tomcat "catalina.sh run" About an hour ago Up About an hour 0.0.0.0:32772->8080/tcp tomcat2
85859d226c8c f796d3d2c195 "catalina.sh run" About an hour ago Up About an hour 0.0.0.0:32771->8080/tcp tomcat1
# 使用tomcat3ping通tomcat2
[root@VM-0-15-centos ~]# docker exec -it tomcat3 ping tomcat2
PING tomcat2 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat2 (172.17.0.3): icmp_seq=1 ttl=64 time=0.093 ms
64 bytes from tomcat2 (172.17.0.3): icmp_seq=2 ttl=64 time=0.068 ms
64 bytes from tomcat2 (172.17.0.3): icmp_seq=3 ttl=64 time=0.069 ms
c64 bytes from tomcat2 (172.17.0.3): icmp_seq=4 ttl=64 time=0.067 ms
^C
--- tomcat2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.067/0.074/0.093/0.012 ms
# 反向使用tomcat2 ping tomcat3
[root@VM-0-15-centos ~]# docker exec -it tomcat2 ping tomcat3
ping: tomcat3: Name or service not known
原理:–link實際上是修改了tomcat3的host文件,如下
[root@VM-0-15-centos ~]# docker exec -it tomcat3 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 tomcat2 d37b518465a0
172.17.0.4 2d8c1363094c
而tomcat2的host文件中沒有這種別名,所以反向通過服務名不能ping通
六、自定義Docker網路
6.1、docker中的網路
查看docker所有的網路:
- briage:橋接網路(也是默認的網路)。通過Docker0作為網橋,實現容器聯網互通
- host:和宿主機共享網路(使用同一塊網卡)
- none:不配置網路,形成一個全封閉的容器,無法和外網連接
- container:讓一個容器共享另一個容器網路相關的namespace,實現讓幾個容器內網路互通
6.2、自定義網路
默認網路參數
# 啟動容器時我們不添加網路相關啟動參數,Docker會為我們補全成下面這樣
# 而這裡指定的 bridge 就是就是docker0
docker run -d -P --name xxx --net bridge imageId
# --net 指定當前容器啟動後加入到哪個網路中
自定義
# 創建自定義網路
# --subnet 192.168.0.0/16 指定了子網網路,可以分配2的16次方-2個ip
# --gateway 192.168.0.1 網關路由器的ip地址
[root@VM-0-5-centos ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
a8a84221d4a73a2e2eda9f692c74af75cdbdac440e8c7587b56847c61e1dde4c
# 查看是否創建成功了
[root@VM-0-5-centos ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
a9ff308438a8 bridge bridge local
0d98ae518a10 host host local
a8a84221d4a7 mynet bridge local
cb71d8cdbbca none null local
查看我們自定義的網路詳情
查看宿主機網卡資訊:可以看到宿主機上多出來了一張虛擬網卡
在自定義的網路中的容器是可以直接通過對方的 容器名 ping通的
七、網路連通
如何讓Docker中兩個不同網路中的容器互通呢?
見上圖,理論上容器1和容器2彼此互通,容器3容器4彼此互通,但是容器12和容器34之間時不互通的,因為他們都不在一個網段中。
具體的作為如下圖:
容器2想ping通容器3或者容器4,本質上是需要將容器2加入到mynet 的網路中。
# 使用connect命令,把一個容器連接到一個網路上
# 查看幫助文檔
[root@VM-0-5-centos ~]# docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.
# 查看connect幫助文檔的使用
[root@VM-0-5-centos ~]# docker network connect --help
Usage: docker network connect [OPTIONS] NETWORK CONTAINER
Connect a container to a network
Options:
--alias strings Add network-scoped alias for the container
--driver-opt strings driver options for the network
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
--link list Add link to another container
--link-local-ip strings Add a link-local address for the container
# 將指定容器添加到指定網路
[root@VM-0-5-centos ~]# docker network connect mynet tomcat1
# 檢查是否添加成功
[root@VM-0-5-centos ~]# docker inspect mynet
[
{
"Name": "mynet",
"Id": "a8a84221d4a73a2e2eda9f692c74af75cdbdac440e8c7587b56847c61e1dde4c",
"Created": "2020-09-18T09:30:17.769656045+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"41976989fbea4138554e131d4067d4eb2bcfb3b6a2491be94af2fd5c64c64256": {
"Name": "tomcat1",
"EndpointID": "6894396881ffbbfe0fcf62da1ffcee304218120207f5b5a27f907bb2c306955b",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
八、參考:
猿大白://www.cnblogs.com/bakari/p/10613710.html