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中設置虛擬機的網路模式時,可以看到

image-20200918081455193

3.1、橋接

橋接模式的本質是:使用一個虛擬的交換機,將虛擬機和物理機網卡打通。他們同屬於一個網段

image-20200918082322318

在這種模式下:有如下特性:

  • 虛擬機和物理機同屬一個網段
  • 虛擬機之間可以相同Ping通
  • 虛擬機和物理機之間可以相互ping通
  • 只要主機能上網,虛擬機就能上網

3.2、NAT

NAT是一種網路地址轉換技術,實現了區域網內的使用自己的本地IP即可聯通互聯網(NAT會將本地Ip,轉換成全球IP)

常見的你家裡的wifi,家裡按了網線之後會有一個公網ip,但是家裡的任何智慧設備通過路由器連接上wifi後都能同時上網,因為路由器會分配給設備一個區域網ip,設備使用這個區域網ip上網,其中的轉換技術就是NAT技術

image-20200918090414954

有如下特性:

  • 主機能上網,虛擬機就能上網
  • 虛擬機直接可以互通

3.3、Host

Host,僅主機,即它是存在於主機內部的一個虛擬網路。

image-20200918091044530

這僅主機模式下,有一塊虛擬網卡,這塊網卡的網段和主機上物理網卡的網段是不相同的。

所有的虛擬機在虛擬網卡的網段下,所以他們彼此直接互通。

默認情況下,虛擬機可以訪問到物理機,但是默認情況下虛擬機不能上網的。(也可以通過修改配置讓他們上互聯網)

3.4、內部網路

在內部網路下,虛擬機和外部完全隔斷,只允許虛擬機之間才能相互訪問

四、Docker0

Docker網路的核心是Docker0

通過ip addr可以看到伺服器中如下幾塊網卡

image-20200917204101504

查看公網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

image-20200917211309301

容器的網卡資訊如下:

image-20200917211400404

可以看到這宿主機和容器其實是在同一個網段的~,所以肯定能通!

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中已經運行了兩個容器了,現在去看下宿主機和兩個容器的網卡資訊。

宿主機:

image-20200917213205238

tomcat1:

image-20200917213244825

tomcat2:

image-20200917213426831

仔細看如上兩圖中多出來的網卡命名對應關係

# 宿主機多出來的:      185: veth79ccfd1@if184
# 對應容器tomcat1:	  184: eth0@if185

# 宿主機多出來的:      187: vethac83886@if186
# 對應容器tomcat2:	  186: eth0@if187

這種網卡成對對應的關係,就是藉助veth-pair技術實現的

veth-pair就是一對虛擬的網路介面,成對出現,一端連著協議,一端彼此相連。由它充當一個橋樑的作用,連接各個Docker 容器,實現網路數據交互

image-20200917215041013

在當前的案例中之間能Ping的

image-20200917222201902

在不指定容器網路的情況下,默認容器使用的Docker0做網橋

通過下面的命令查看使用Docker0的所有Container

image-20200917223906864

image-20200917224026778

Docker會為容器分配一個可用的ip

分配的ip都在上圖規定的subnet子網網段下的格式:172.17.0.2/16

在上面劃分子網時有提到這種劃分的方式,最後的16為它的網路號,也就是說他還有16位的機器號,也就是2的16次方-2個

前面的驗證了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所有的網路:

image-20200918080638181

  • 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

查看我們自定義的網路詳情

image-20200918093535139

查看宿主機網卡資訊:可以看到宿主機上多出來了一張虛擬網卡

image-20200918093721195

在自定義的網路中的容器是可以直接通過對方的 容器名 ping通的

七、網路連通

如何讓Docker中兩個不同網路中的容器互通呢?

image-20200918095046292

見上圖,理論上容器1和容器2彼此互通,容器3容器4彼此互通,但是容器12和容器34之間時不互通的,因為他們都不在一個網段中。

具體的作為如下圖:

image-20200918095115470

容器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

Tags: