1. 程式人生 > 其它 >Docker進階一:網路篇

Docker進階一:網路篇

理解Docker0

檢視本地ip ip addr

[root@VM-0-6-centos ~]# 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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
#阿里雲的私有IP
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:9a:88:4d brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.6/20 brd 172.17.15.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe9a:884d/64 scope link 
       valid_lft forever preferred_lft forever
# docker網橋
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:d1:ba:72:7a brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:d1ff:feba:727a/64 scope link 
       valid_lft forever preferred_lft forever

Docker 是如何處理容器網路訪問的?

我們之前安裝ES的時候,留過一個問題,就是安裝Kibana的問題,Kibana得指定ES的地址!或者我們實際場景中,我們開發了很多微服務專案,那些微服務專案都要連線資料庫,需要指定資料庫的url地址,通過ip。但是我們用Docker管理的話,假設資料庫出問題了,我們重新啟動執行一個,這個時候資料庫的地址就會發生變化,docker會給每個容器都分配一個ip,且容器和容器之間是可以互相訪問的。 我們可以測試下容器之間能不能ping通過。

[root@VM-0-6-centos ~]# docker run -d -P --name tomcat01 tomcat
# 檢視tomcat01的ip地址,docker會給每個容器都分配一個ip!
[root@VM-0-6-centos ~]#  docker exec -it tomcat01 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
24: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever
# 可以ping通!
[root@VM-0-6-centos ~]# ping 172.18.0.2

原理

每一個安裝了 Docker 的 linux 主機都有一個 docker0 的虛擬網絡卡。這是個橋接網絡卡,使用了 veth-pair 技術!

  • 再次檢視主機的 ip addr :本來有三個網路,啟動tomcat容器之後,會多了一個網路!

  • 每啟動一個容器,linux主機就會多了一個虛擬網絡卡。

    #啟動一個tomcat01,主機的ip地址多了個  25: veth2b7cb71@if24
    #然後我們在tomcat01容器中檢視容器的ip  24: eth0@if25
    
    #我們再啟動一個tomcat02觀察
    [root@VM-0-6-centos ~]# docker run -d -P --name tomcat02 tomcat
    
    # 然後發現linux主機上又多了一個網絡卡	27: veth4d2bd95@if26
    # 我們看下tomcat02的容器內ip地址是	  26: eth0@if27
    [root@VM-0-6-centos ~]# docker exec -it tomcat02 ip addr
    

    可以發現:只要啟動一個容器,就有一對網絡卡

    veth-pair 就是一對的虛擬裝置介面,它都是成對出現的。一端連著協議棧,一端彼此相連著。

    正因為有這個特性,它常常充當著一個橋樑,連線著各種虛擬網路裝置!

    “Bridge、OVS 之間的連線”,“Docker 容器之間的連線” 等等,以此構建出非常複雜的虛擬網路結構,比如 OpenStack Neutron。

  • 我們來測試下 tomcat01 和 tomcat02 容器間是否可以互相 ping 通

    [root@VM-0-6-centos ~]# docker exec -it tomcat02 ping 172.18.0.2
    PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
    64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.095 ms
    

    所以:容器和容器之間是可以互相訪問的。

    結論:tomcat1 和 tomcat2 共用一個路由器。是的,他們使用的一個,就是docker0。任何一個容器啟動預設都是 docker0 網路。 docker 預設會給容器分配一個可用 ip 。

小結

Docker使用Linux橋接,在宿主機虛擬一個Docker容器網橋(docker0),Docker啟動一個容器時會根據 Docker網橋的網段分配給容器一個IP地址,稱為Container-IP,同時Docker網橋是每個容器的預設網 關。因為在同一宿主機內的容器都接入同一個網橋,這樣容器之間就能夠通過容器的Container-IP直接 通訊。

Docker 容器網路就很好的利用了 Linux 虛擬網路技術,在本地主機和容器內分別建立一個虛擬介面,並讓他們彼此聯通(這樣一對介面叫 veth pair);

Docker 中的網路介面預設都是虛擬的介面。虛擬介面的優勢就是轉發效率極高(因為Linux是在核心中進行資料的複製來實現虛擬介面之間的資料轉發,無需通過外部的網路裝置交換),對於本地系統和容器系統來說,虛擬介面跟一個正常的乙太網卡相比並沒有區別,只是他的速度快很多。

Link引數

思考一個場景,我們編寫一個微服務,資料庫連線地址原來是使用ip的,如果ip變化就不行了,那我們能不能使用服務名訪問呢?

就像 jdbc:mysql://mysql:3306,這樣的話哪怕 mysql 重啟,我們也不需要修改配置了!

docker提供了 --link 的操作!

# 我們使用tomcat02,直接通過容器名ping,不使用ip
[root@VM-0-6-centos ~]# docker exec -it tomcat02 ping tomcat01
# ping 不通
ping: tomcat01: Name or service not known

#我們再啟動一個tomcat03,但是啟動的時候連線tomcat02
[root@VM-0-6-centos ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
80ed9c4e1f9428598a91c727ed13b7d0534d86d569855d4fb8739baabe5d6b91

#這個時候,我們就可以使用tomcat03 ping通 tomcat02 了
[root@VM-0-6-centos ~]#  docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.18.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.18.0.3): icmp_seq=1 ttl=64 time=0.092 ms

# tomcat3 ping不通 tomcat1
[root@VM-0-6-centos ~]# docker exec -it tomcat03 ping tomcat01
ping: tomcat01: Name or service not known
# tomcat2 ping不通 tomcat3 反向也ping不通
[root@VM-0-6-centos ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known

這是為什麼呢?

#進入tomcat03中檢視下host配置檔案
[root@VM-0-6-centos ~]# docker exec -it tomcat03 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
#發現tomcat2直接被寫在這裡
172.18.0.3	tomcat02 cff25f666b32
172.18.0.4	80ed9c4e1f94

所以這裡其實就是配置了一個 hosts 地址而已!

原因:--link 的時候,直接把需要 link 的主機的域名和 ip 直接配置到了 hosts 檔案中了

--link 早都過時了,我們不推薦使用!我們可以使用自定義網路的方式

自定義網路(重要)

基本概念

指令列表

[root@VM-0-6-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.

檢視所有網路

[root@VM-0-6-centos ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
4b873066daf7   bridge    bridge    local
86da632adad6   elastic   bridge    local
64b606f257e7   host      host      local
34ab4fdb73c0   none      null      local

所有網路模式

網路模式 配置 說明
bridge模式 --net=bridge 預設值,在 Docker 網橋 docker0 上為容器建立新的網路棧
none模式 --net=none 不配置網路,使用者可以稍後進入容器,自行配置
container 模式 -- net=container:name/id 容器和另外一個容器共享Network namespace。 kubernetes中的pod就是多個容器共享一個Network namespace。
host模式 --net=host 容器和宿主機共享Network namespace
使用者自定義 --net=自定義網路 使用者自己使用network相關命令定義網路,建立容器的 時候可以指定為自己定義的網路,就像 elastic

檢視一個具體的網路的詳細資訊

[root@VM-0-6-centos ~]# docker network inspect 4b873066daf7
[
    {
        "Name": "bridge",
        "Id": "4b873066daf7eca3fd7a79ce17b46dff17a89368cb7f43d01c88dd9ee08d9407",
        "Created": "2021-06-11T18:42:36.937993641+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                //預設 docker0 是管理這個子網範圍內的。0~16,
                //也就是 255*255,去掉0個255,我們有65534可以分配的ip
                //所以 docker0 網路預設可以支援建立6萬多個容器ip不重複
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "220fac5f16f3cf7f2619131502cb6bb4004f334c3b501a0ceff8804c361cf027": {
                "Name": "tomcat01",
                "EndpointID": "d54c9b71aff1843c3a1609de8eaa85785ebddd8a419ea5fae346fb538568946f",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "80ed9c4e1f9428598a91c727ed13b7d0534d86d569855d4fb8739baabe5d6b91": {
                "Name": "tomcat03",
                "EndpointID": "a6dd8dd8ba2b5b341cbed8318a2463a4e28f1059cc848504a409fbf75ae21f4f",
                "MacAddress": "02:42:ac:12:00:04",
                "IPv4Address": "172.18.0.4/16",
                "IPv6Address": ""
            },
            "cff25f666b32df808923a51e14f2f2686fc9aff161e07c188c28ce15d0b38401": {
                "Name": "tomcat02",
                "EndpointID": "b5b18a038166b64a0308cc4a506f543b92d35b9fc50f5758f8d5daccc1df87bd",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

自定義網絡卡

1、先刪除之前建立的 tomcat 映象以及容器

2、建立容器

但是我們知道預設建立的容器都是 docker0 網絡卡的

#預設值 --net bridge 使用的docker0
docker run -d -P --name tomcat01 --net bridge tomcat

docker0網路的特點

  1. 它是預設的
  2. 域名訪問不通
  3. --link 域名通了,但是刪了又不行

3、我們可以讓容器建立的時候使用自定義網路

自定義建立的預設default "bridge" 一個網路

docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
[root@VM-0-6-centos ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
4b873066daf7   bridge    bridge    local
64b606f257e7   host      host      local
7f9fbfea6931   mynet     bridge    local
34ab4fdb73c0   none      null      local
[root@VM-0-6-centos ~]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "7f9fbfea6931271e917c7a932c47d05f311f2fe6f1e694b95e4ef3fcf060446e",
        "Created": "2021-06-16T15:56:58.841772626+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": {},
        "Options": {},
        "Labels": {}
    }
]

我們來啟動兩個容器測試,使用自己的 mynet

docker run -d -P --name tomcat-net-01 --net mynet tomcat
docker run -d -P --name tomcat-net-02 --net mynet tomcat

來測試ping容器名和ip試試

# 都可以ping通
[root@VM-0-6-centos ~]# docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.118 ms
[root@VM-0-6-centos ~]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.059 ms

發現,我們自定義的網路docker都已經幫我們維護好了對應的關係

所以我們平時都可以這樣使用網路,不使用 --link 效果一樣,所有東西實時維護好,直接域名 ping 通。

網路連通

docker0和自定義的網路使用的不是同一個網橋,肯定不通,我們使用自定義網路的好處就是網路隔離:

大公司專案部署的業務都非常多,假設我們有一個商城,我們會有訂單業務(操作不同資料),會有訂單業務購物車業務(操作不同快取)。如果在一個網路下,有的程式猿的惡意程式碼就不能防止了,所以我們就在部署的時候網路隔離,建立兩個橋接網絡卡,比如訂單業務(裡面的資料庫,redis,mq,全部業務都在 order-net 網路下)其他業務在其他網路。

那關鍵的問題來了,如何讓兩個不同的網路互相訪問呢,如何讓 tomcat-net-01 訪問 tomcat1?

# 啟動預設的容器,在docker0網路下
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat02 tomcat

有個命令 connect 用來連線網路

# 我們來測試一下!打通mynet-docker0
[root@VM-0-6-centos ~]# docker network connect mynet tomcat01
[root@VM-0-6-centos ~]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "7f9fbfea6931271e917c7a932c47d05f311f2fe6f1e694b95e4ef3fcf060446e",
        "Created": "2021-06-16T15:56:58.841772626+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": {
            "52395d45d1fcad0170da201db471ea6ac75c25c9f7d91d10b6260dce2739fd54": {
                "Name": "tomcat-net-01",
                "EndpointID": "3c1aea820c4276b0d0dbe249ebd6f43547baceb7c3e774f8ee4b61b0e4b0b11f",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            },
            //發現我們的tomcat01就進來這裡了
            "c159a99201d5b3f0f6be065d562c1a0e6439b316084361937f9eda9a22e997ab": {
                "Name": "tomcat01",
                "EndpointID": "e11948dcd704e50b8008ee41546ff7c9f506b636f41fb6e6697081fd9d398dc5",
                "MacAddress": "02:42:c0:a8:00:04",
                "IPv4Address": "192.168.0.4/16",
                "IPv6Address": ""
            },
            "f2106d157b5ea6c5bdb87e04b9dc18be2b2e25a41d61e25851ea0afbf1e9ea39": {
                "Name": "tomcat-net-02",
                "EndpointID": "3cb8b199df4fca69e1a6428ae0536ff3291f9215f8b9d9303a2ec3402bdc704f",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

tomcat01 可以ping通了

[root@VM-0-6-centos ~]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.075 ms

tomcat02 依舊ping不通,因為之前只連線了tomcat01

[root@VM-0-6-centos ~]#  docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known

結論:如果要跨網路操作別人,就需要使用 docker network connect [OPTIONS] NETWORK CONTAINER 連線