說明:該篇博客是博主一字一碼編寫的,實屬不易,請尊重原創,謝謝大家!
文章目錄
一、概述
1.單機和多機
2.環境搭建
說明:需要兩臺裝有docker的linux(centos7)機器,之前博主在Docker Playground的使用(2020實操圖解)中有詳細說明安裝方式:第一種是通過VirtualBox或者VMware虛擬化軟件直接創建Linux虛擬機,在虛擬機裏安裝使用Docker;第二種是通過Vagrant + VirtualBox快速搭建Docker Host(推薦使用);第三種是通過Docker-Machine快速搭建Docker Host,博主這裏是採用第一種VMware虛擬化軟件直接創建Linux虛擬機,並在虛擬機中安裝了docker。
現在博主給大家演示一下第二種推薦方式Vagrant + VirtualBox快速搭建兩臺安裝docker的centos7機器
2.1 配置Vagrantfile
- 首先初始化Vagrantfile文件
- 在Vagrantfile文件中,進入如下配置
- 在centos7目錄下創建setup.sh文件,文件內容如下,就是在搭建好的centos7機器中執行的命令
2.2 快速搭建兩臺centos7
- 爲了節約時間,提前在vagrant官網下載好了centos7的virtualbox.box鏡像文件,將其拷貝到centos7目錄下,設置添加本地box鏡像文件
- 一切準備就緒,執行vagrant up命令即可,過程時間比較長
- 搭建完成,查看virtualbox,顯示搭建的docker-node1和docker-node2兩天centos7正在運行
- 通過vagrant命令查看虛擬機狀態,顯示正在運行
- 進入docke-node1虛擬機中,查看ip地址與vagrantfile中設定的一致
- 進入docke-node2虛擬機中,查看ip地址與vagrantfile中設定的一致
- 以上方式是爲了給大家進程操作演示,前面也說了博主是使用VMware來搭建兩臺安裝docker的centos7虛擬機,除了這兩種方式還可以通過docker-machine來create創建安裝docker的linux虛擬機或者是直接使用mac或windows本機上的docker,但是這種方式不建議,推薦以上Vagrant + VirtualBox方式或者是跟博主一樣使用VMware開啓兩臺裝有docker的linux虛擬機(前提你的電腦配置玩得轉),下面則是博主使用虛擬工具VMware搭建裝有docker的centos7虛擬機
3.網絡基礎
3.1 網絡分層的概念
網絡層次可劃分爲五層因特網協議棧和七層因特網協議棧,具體可以參考百度百科
3.2 路由的概念
路由(routing)是指分組從源到目的地時,決定端到端路徑的網絡範圍的進程,具體可以參考百度百科
3.3 IP地址和路由
3.3 公有IP和私有IP
3.4 網絡地址轉換NAT
3.5 ping和telnet
ping: 驗證IP的可達性
- 分別ping以下兩個IP,一個能ping通丟包率爲0,一個不能ping通丟包率爲100%
telnet: 驗證服務的可用性
- 分別telnet同一IP不同端口,一個成功,另一個不成功
- 有時候會出現一些網站不能ping通但是一樣可以正常訪問,那麼這種情況就要使用telnet來驗證服務的可用性了
二、Linux Network Namespace
1.Container Network Namespace
- 首先直接拉取一個busybox鏡像,這個鏡像是基於linux的,非常小的
- 然後通過後臺運行busybox容器,並在容器中執行一個無限循環shell命令
- 緊接着通過exec交互式進入到容器中執行/bin/sh命令,查看該容器中的網絡接口,一共有兩個分別是lo(local)和eth(網卡),這個就是網絡的Namespace(命名空間)
- 退出容器,在本地centos7機器上查看網絡接口,可以發現有很多個網絡接口,對比容器中的Network Namespace是隔離開的,通過linux network namespace實現了容器和本機網絡的隔離
- 同理再次創建一個容器,查看網絡也是隔離開的
- 這兩臺容器,都是可以互相ping通的,那麼說明兩個獨立的network namespace是可以互相ping通的
2.Create && Delete Network Namespace
- 查看本機已有的network namespace
sudo ip netns list
- 創建一個名爲test1的network namespace
sudo ip netns add test1
- 刪除名爲test1的network namespace
sudo ip netns delete test1
- 創建test1和test2兩個網絡命名空間,並查看網絡接口,發現只有lo接口,並且狀態爲DOWN停止
sudo ip netns exec test1 ip a
sudo ip netns exec test2 ip a
- 還可以通過ip link來查看本機和兩個創建好的network namespace網絡接口
sudo ip netns exec test1 ip link
sudo ip netns exec test2 ip link
3.Network Namespace + veth-pair
說明: 目前創建好的兩個network namespace爲test1和test2,這兩個網絡命名空間分別都有一個本地迴環口lo,並且狀態爲DOWN停止,現在需要將這兩個迴環口lo的狀態修改爲up,並且使這兩個網絡命名空間進行相連,那麼要想這兩個namespace相連則需要創建veth-pair(一對虛擬設備接口),將這一對虛擬設備接口分別放一個在test1和test2中,那麼這樣就能實現兩個網絡命名空間相連
- 首先設置test1的狀態爲up,但是設置後發現爲UNKNOWN,之所以UP不起來是這個接口是需要兩端進行連接的,就好比虛擬機linux eth33要與本機windows的虛擬化端口進行連接一樣的道理,也就是說單個端口是無法UP起來的必須是一對
sudo ip netns exec test1 ip link set dev lo up
- 現在則需要去創建一對veth-pair設備接口,分別是veth-test1和veth-test2,對比創建之前和創建之後,linux本機上的ip link
sudo ip link add veth-test1 type veth peer name veth-test2
- 現在將veth-test1接口添加到namespace test1裏面去,然後查看test1 這個namespace顯示添加veth-test1接口成功,並且linux本機上的veth-test1接口不見了
sudo ip link set veth-test1 netns test1
- 同理將veth-test2接口添加到namespace test2裏面
sudo ip link set veth-test2 netns test2
- 查看test1和test2兩個namespace的以上添加的接口,狀態都是DOWN,並且沒有IP地址
sudo ip netns exec test1 ip link
sudo ip netns exec test2 ip link
- 即所以爲這兩個端口添加IP地址,再次查看test1和test2的ip link發現狀態還是DOWN(說明博主這裏之前IP設置有問題,所以刪除重頭來過,導致這裏添加的端口索引從6,7變成了8,9)
sudo ip netns exec test1 ip addr add 192.168.88.1/24 dev veth-test1
sudo ip netns exec test2 ip addr add 192.168.88.2/24 dev veth-test2
- 那麼當設置完namespace ip後,則需要設置namespace 狀態爲UP
sudo ip netns exec test1 ip link set dev veth-test1 up
sudo ip netns exec test2 ip link set dev veth-test2 up
- 此時,查看test1 和 test2 namespace的ip地址,就是我們當初設置的ip
sudo ip netns exec test1 ip a
sudo ip netns exec test2 ip a
- 在test1 namespace中ping test2 namespace 端口IP 以及在test2 namespace中ping test1 namespace 端口IP ,都是可以互相ping通的
sudo ip netns exec test1 ping 192.168.88.2
sudo ip netns exec test2 ping 192.168.88.1
三、Docker Bridge Network
說明:在上面目錄二中博主是通過創建veth-pair一對接口來讓兩個namespace進行互相連接的,那麼現在就來看看docker container是怎麼進行連接的,不明白的可以參閱官方文檔
1.驗證Container連接
- 之前博主創建了兩個基於busybox image名爲test1和test2的容器,因爲博主關機過,所以這裏需要重啓啓動這兩個容器
- 查看test1和test2容器的IP地址,那麼這兩個容器肯定是能互相ping通的
2.Bridge Network
2.1 查看bridge網絡數據
- 爲了查看效果,博主將運行的test2 容器進行刪除,然後來查看本地centos的網絡信息
sudo docker network ls
- 查看本地linux bridge網絡,可以發現docker這個test1容器是連接在bridge網絡上的,在containers鍵中顯示出包含的docker容器信息
sudo docker network inspect <network id/name>
- 查看linux本機的網絡接口以及test1 容器的網絡接口,其中基於busybox image創建的容器本身是有一個自己的network namespace的,與本機docker0(docker0的network namespace就是本機centos機器)這個bridge網絡也是通過veth-pair(也就是vethe125f42@if10和eth0@if11)來進行連接test1這個容器的network namespace
2.2 驗證container通過veth連接到docker0
- 通過brctl工具來查詢網橋信息,可以發現docker0這個bridge的interface接口爲本機linux機器的vethe125f42,也就是說這個接口是連接到linux bridge上的
sudo yum install bridge-utils
brctl show
- 因爲之前博主刪除了test2容器,現在再次進行創建
sudo docker run -d --name test2 busybox /bin/sh -c "while true; do sleep 3000; done;"
- 此時驗證是否添加到linux bridge網絡中
sudo docker network inspect bridge
- 查看docker0這個bridge多了一個interface接口vethfdba8dd指向了本機的接口vethfdba8dd@if16形成了一對veth-pair來讓test2容器的network namespace與本機docker0 network namespace進行相連接
- 關於以上test1、test2容器的network namespace與本機docker0 network namespace是通過一對veth-pair進行相連的,架構圖如下,就相當於在自己家裏有兩臺設備同時連接到一臺路由器上或者交換機上,即使沒有連接外網,這兩臺設備也是可以通過局域網進行互相通信的
2.3 container連接到外網
- 首先容器能夠連接到外網,肯定是本機linux機器能夠連接到外網才行,本機比如是通過eth0端口來進行外網訪問,那麼容器是可以通過連接到docker0 這個bridge做一個NAT網絡地址轉換成eth0端口,那麼就可以作爲linux主機的數據包發送到internate了,即就可以訪問外網了
四、Container Link && Create Custom Bridge
說明: 有這麼一個需求場景,後臺項目需要訪問數據庫mysql,那麼就需要這個數據庫的地址以及端口號(固定的),創建兩個容器
一個容器是運行數據庫服務,另一個容器是運行後臺服務,這個後臺服務是需要去訪問數據庫,那麼通過docker inspect <container id/name>來查看運行數據庫服務的容器ip,運行後臺服務的容器將數據庫服務的容器ip傳進去作爲數據庫參數,這樣才能連接到數據庫容器裏面,但是這種方式是不可取的,因爲在寫代碼時,根本不知道數據庫容器的ip是多少,那麼可以通過在創建數據庫容器時給這個容器取一個名字,如果通過這個名字可以直接訪問數據庫容器,那麼就不需要通過ip來進行訪問了,實現方式這是通過docker link機制,在創建第二個容器時候,可以把它link到第一個容器上面,這樣訪問第一個容器時候,就可以直接通過name進行訪問了
1.通過創建link的方式ping通容器name
- 首先先進入到test2這個容器中,通過ping test1容器的ip是可以ping通的,但是ping test1這個name是無法ping通的
- 現在刪除test2容器,然後重新創建test2容器並將其link到test1上面,ping test1就可以ping通了,那麼直接通過test1:3306就可以訪問數據庫了
2.通過創建bridge的方式ping通容器name
- 刪除test2容器,重新創建最初的test2,不使用link
sudo docker run -d --name test2 busybox /bin/sh -c "while true; do sleep 3000; done;"
- 查看目前本機的network,然後創建一個bridge driver 名我my-bridge
sudo docker network create -d bridge my-bridge
- 創建bridge成功後,通過brctl show命令來查看本機的網橋信息,其bridge name的後面字段則是這個bridge對應的network id,需要注意的是目前這個bridge name爲f1ccd24e9751的網橋並沒有interface接口,原因還沒有讓容器使用我們創建的bridge
sudo docker network ls
brctl show
- 創建一個名爲test3並不使用默認docker0這個bridge而是使用我們自己創建的my-bridge的容器
sudo docker run -d --name test3 --network my-bridge busybox /bin/sh -c "while true; do sleep 3000; done;"
- 再次查看網橋信息,我們創建的網橋則就有test3這個容器的接口了
ip link
brctl show
- 查看創建的my-bridge的元數據,可以看到容器test3已經連接到這個bridge上了
sudo docker network inspect my-bridge
- 對於之前已經創建好的test1和test2容器,還是可以將其link到我們新建的my-bridge上,可以直接輸入sudo docker network回車就能出現其命令幫助,connect命令可以將指定的容器連接到指定network上
sudo docker network
sudo docker network --help
- 將test2連接到my-bridge上,並查看my-bridge元數據,顯示test2容器連接成功
sudo docker network connect my-bridge test2
sudo docker network inspect my-bridge
- 因爲之前創建test1和test2容器時,已經默認將其連接到bridge上了,現在又將test容器設置連接到創建的bridge上面,所以查看bridge元數據,結果發現test2也在這個bridge上面,所以test2這個容器即屬於默認的bridge又屬於我們創建的my-bridge
sudo docker network inspect bridge
- 現在分別進入test2和test3 /bin/sh中,分別ping test3和test2容器的IP都是可以ping通的,但是居然無法通過容器name ping通,這就很奇怪了,因爲dokcer官網上說的是將兩個容器添加到自定義創建的bridge後,容器之間是可以通過name進行訪問的
sudo docker exec -it test3 /bin/sh
sudo docker exec -it test2 /bin/sh
- 導致以上連接到自己創建的bridge上兩個容器test2和test3不能互相通過容器name ping通的原因,博主猜想是因爲image原因,所以博主這裏重新換個centos最新版本鏡像進行嘗試,博主在之前文章中已經安裝過centos鏡像了,所以可以直接通過image創建容器,刪除所有容器以及刪除創建的my-bridge
sudo docker network rm my-bridge
- 執行如下命令,也就是重複之前操作,但是這次是創建的容器是基於centos
docker run -d --name test1 centos /bin/sh -c "while true; do sleep 3000; done"
docker run -d --name test2 centos /bin/sh -c "while true; do sleep 3000; done"
sudo docker network create -d bridge my-bridge
docker run -d --name test3 --network my-bridge centos /bin/sh -c "while true; do sleep 3000; done"
sudo docker network connect my-bridge test2
- 查看my-bridge元數據,驗證test2和test3容器連接到此bridge
sudo docker network inspect my-bridge
- 現在進入test3和test2容器shell裏面,互相ping對方容器的ip以及name,證明通過容器name進行ping通的,之前博主猜想busybox鏡像導致的是正確的
sudo docker exec -it test3 /bin/sh
sudo docker exec -it test2 /bin/sh
- 現在將test1容器連接到my-bridge中,來驗證三臺容器都能通過name互相ping 通
sudo docker network connect my-bridge test1
- 分別進入test1、test2、test3 容器shell中互相通過容器name都是能ping通的,原因是test1、test2以及test3這兩個容器都連接到我們創建的my-bridge中,所以才能夠互相ping通的
sudo docker exec -it test3 /bin/sh
sudo docker exec -it test2 /bin/sh
sudo docker exec -it test1 /bin/sh