[Docker 系列]docker 學習八,Docker 網路

小魔童哪吒發表於2021-12-01

開始理解 docker

一開始,我們們思考一下,宿主機怎麼和容器通訊呢?

說容器之間是相互隔離的,那麼他們是否可以通訊?又是如何通訊的呢?

開始探索

我們先來看看我們環境中的映象都有些啥,有 xmtubuntu

# docker images
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
xmtubuntu             latest    c3e95388a66b   38 seconds ago   114MB

再來看看宿主機的網路卡資訊

ip addr來檢視我們們宿主機的網路卡資訊

我們發現有一個docker0,是因為我們的宿主機上面安裝了docker 的服務,docker 會給我生成一個虛擬網路卡,圖中的這個 docker0就是虛擬網路卡資訊

建立並啟動一個docker 命名為 ubuntu1

docker run -it --name ubuntu1 -P xmtubuntu

檢視一下宿主機網路卡資訊

檢視宿主機的網路卡資訊

再檢視 ubuntu1 的網路卡資訊,docker 也會預設給我們的容器分配ip 地址

可以發現宿主機的網路卡資訊 docker0 下面多了117: veth838e165@if116:ubuntu1的網路卡資訊上也正好有116: eth0@if117

我們發現這些veth的編號是成對出現的,我們們的宿主機就可以和 ubuntu1進行通訊了

使用宿主機(docker0)和ubuntu1互相 ping

docker0pingubuntu1 ok

ubuntu1pingdocker0,同樣的 ok

我們們可以嘗試再建立並啟動一個docker 命名為 ubuntu2,方法和上述完全一致

# docker run -it -P --name ubuntu2 xmtubuntu

進入容器,使用ip a檢視到ubuntu2的網路卡資訊

宿主機上面檢視網資訊


宿主機上面又多了一個 veth , 119: veth0b29558@if118

ubuntu2上的網路卡資訊是118: eth0@if119,他們同樣是成對出現的,小夥伴看到這裡應該明白了吧

ubuntu1 ping ubuntu2 呢?

ubuntu1 對應 172.18.0.2

ubuntu2 對應 172.18.0.3

# docker exec -it ubuntu1 ping 172.18.0.3
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.071 ms
64 bytes from 172.18.0.3: icmp_seq=2 ttl=64 time=0.070 ms
64 bytes from 172.18.0.3: icmp_seq=3 ttl=64 time=0.077 ms

仍然是可以通訊,非常 nice

原理是什麼?

上述的探索,我們發現宿主機建立的容器,都可以直接ping通宿主機,那麼他們的原理是啥呢?

細心的 xdm 應該可以看出來,上述的例子中,veth是成對出現的,上述宿主機和容器能夠進行網路通訊,得益於這個技術veth-pair

veth-pair

*veth-pair *是一對虛擬裝置介面,他們都是成對出現的,一段連著協議,一段彼此相連

正是因為這個特性,veth-pair在此處就是充當了一個橋樑,連線各種虛擬裝置

通過上圖我們可以得出如下結論:

  • ubuntu1ubuntu2他們是公用一個路由器,也就是 docker0,ubuntu1 能pingubuntu2是因為 docker0 幫助其轉發的
  • 所有的容器在不指定路由的情況下,都是以 docker0 作為路由,docker 也會給我們的容器分配一個可用的 ip
  • docker0 是在宿主機上面安裝 docker 服務就會存在的

那麼通過上圖我們就知道,容器和宿主機之前是通過橋接的方式來打通網路的。

Dcoker 中所有的網路介面都是虛擬的,因為虛擬的轉發效率高呀,當我們刪除某一個容器的時候,這個容器對應的網路卡資訊,也會被隨之刪除掉

那麼我們可以思考一下,如果都是通過找ip地址來通訊,如果 ip變化了,那麼我們豈不是找不到正確的容器了嗎?我們是否可以通過服務名來訪問容器呢?

–link

當然是可以的,當我們在建立和啟動容器的時候加上–link就可以達到這個效果

我們再建立一個容器 ubuntu3,讓他 link 到 ubuntu2

# docker run -it --name ubuntu3 -P --link ubuntu2 xmtubuntu

# docker exec -it ubuntu3 ping ubuntu2
PING ubuntu2 (172.18.0.3) 56(84) bytes of data.
64 bytes from ubuntu2 (172.18.0.3): icmp_seq=1 ttl=64 time=0.093 ms
64 bytes from ubuntu2 (172.18.0.3): icmp_seq=2 ttl=64 time=0.085 ms
64 bytes from ubuntu2 (172.18.0.3): icmp_seq=3 ttl=64 time=0.092 ms
64 bytes from ubuntu2 (172.18.0.3): icmp_seq=4 ttl=64 time=0.073 ms

很明顯,我們可以到看到 ubuntu3可以通過服務名ubuntu2直接和ubuntu2通訊,但是反過來是否可以呢?

# docker exec -it ubuntu2 ping ubuntu3
ping: ubuntu3: Name or service not known

不行?這是為什麼呢?

我們來檢視一下 ubuntu3的本地 /etc/hosts檔案就清楚了

看到這裡,這就清楚了 link 的原理了吧,就是在自己的 /etc/hosts檔案中,加入一個host而已,這個知識點我們可以都知悉一下,但是這個 link 還是好搓,不好,他需要在建立和啟動容器的時候使用,用起來不方便

那麼我們有沒有更好的辦法的呢?

自定義網路

可以使用 docker network ls檢視宿主機 docker 的網路情況

:~# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
8317183dfc58   bridge    bridge    local
997107487c6b   host      host      local
ab130876cbe6   none      null      local

網路模式

  • bridge

橋接,docker0 預設使用 bridge 這個名字

  • host

和宿主機共享網路

  • none

不配置網路

  • container

容器網路連通,這個模式用的非常少,因為侷限性很大

現在我們們可以自定義個網路,來連通兩個容器

自定義網路

自定義一個 mynet 網路

# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
9a597fc31f1964d434181907e21ff7010738f3f7dc35ba86bf7434f05a6afc4a
  • docker network create

建立一個網路

  • –driver

指定驅動是 bridge

  • –subnet

指定子網

  • –gateway

指定閘道器

此處我們設定子網是--subnet 192.168.0.0/16,閘道器是192.168.0.1,那麼我們剩下可以使用的ip就是 192.168.0.2 – 192.168.255.254192.168.255.255是廣播地址

清空已有的容器

清空所有測試的容器,減去干擾

建立並啟動2個容器,分別是ubuntu1 和 ubuntu2

# docker run -it -P --name ubuntu1 --net mynet xmtubuntu
# docker run -it -P --name ubuntu2 --net mynet xmtubuntu

此時我們可以檢視一下宿主機的網路卡資訊,並驗證兩個容器直接通過容器名字是否可以通訊

我們思考一下自定義網路的好處

我們們自定義 docker 網路,已經幫我們維護好了對應關係,這樣做的好處是容器之間可以做到網路隔離,

例如

一堆 redis 的容器,使用 192.168.0.0/16 網段,閘道器是 192.168.0.1

一堆 mongodb的容器,使用 192.167.0.0/16 網段,閘道器是 192.167.0.1

這樣就可以做到子網很好的隔離開來,不同的叢集使用不同的子網,互不影響

那麼子網間是否可以打通呢?

網路連通

兩個不同子網內的容器如何連通了呢?

我們絕對不可能讓不同子網的容器不通過路由的轉發而直接通訊,這是不可能的,子網之間是相互隔離的

但是我們有辦法讓 ubuntu3 這個容器通過和 mynet 打通,進而轉發到 ubuntu1 或者 ubuntu2 中就可以了

打通子網

我們檢視 docker network 的幫助手冊

docker network -h

image-20210807203841520

可以使用 docker network connect命令實現,在檢視一下幫助文件

# docker network connect -h
Flag shorthand -h has been deprecated, please use --help

Usage:  docker network connect [OPTIONS] NETWORK CONTAINER

Connect a container to a network

開始打通

docker network connect mynet ubuntu3

這個時候我們可以檢視一下 mynet 網路的詳情

# docker network inspect mynet

可以看到在 mynet 網路上,又增加了一個容器,ip 是 192.168.0.4

沒錯,docker 處理這種網路打通的事情就是這麼簡單粗暴,直接在 ubuntu3 容器上增加一個虛擬網路卡,讓 ubuntu3 能夠和 mynet 網路打通

宿主機當然也相應的多了一個veth

![](gitee.com/common_dev/mypic/raw/ master/image-20210807204514806.png)

現在,要跨網路操作別人的容器,我們就可以使用 docker network connect的方式將網路打通,開始幹活了

大家對網路還感興趣嗎,哈哈,關於 docker 的前幾期文章連結如下,可以逐步學習,慢慢深入,多多回顧

【Docker 系列】docker 學習 五,我們來看看容器資料捲到底是個啥

【Docker 系列】docker 學習 四,一起學習映象相關原理

【Docker 系列】docker 學習 三,docker 初步實戰和 docker 視覺化管理工具試煉

【Docker 系列】docker 學習 二,docker 常用命令,映象命令,容器命令,其他命令

【Docker 系列】docker 學習 一,Docker的安裝使用及Docker的基本工作原理 | 8月更文挑戰

參考資料:

docker docs

歡迎點贊,關注,收藏

朋友們,你的支援和鼓勵,是我堅持分享,提高質量的動力

好了,本次就到這裡

技術是開放的,我們的心態,更應是開放的。擁抱變化,向陽而生,努力向前行。

我是小魔童哪吒,歡迎點贊關注收藏,下次見~

本作品採用《CC 協議》,轉載必須註明作者和本文連結
關注微信公眾號:小魔童哪吒

相關文章