萬字長文深入理解Docker鏡像分層原理、容器數據卷、網絡通信架構(Docker系列第2章,共3章)

鏡像分層的簡單直觀體現

在執行docker pull時,會發現多個Pull complete 字樣,就能體現分層,如果是一個文件,只會有一個Pull complete 。

docker pull redis
Using default tag: latest
latest: Pulling from library/redis
a2abf6c4d29d: Already exists 
c7a4e4382001: Pull complete 
4044b9ba67c9: Pull complete 
c8388a79482f: Pull complete 
413c8bb60be2: Pull complete 
1abfd3011519: Pull complete 
Digest: sha256:db485f2e245b5b3329fdc7eff4eb00f913e09d8feb9ca720788059fdc2ed8339
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest

文件系統

  • 概念:文件系統是計算機系統中用于組織和管理數據存儲的一種方式。它定義了數據如何存儲、命名、訪問和修改的方式。
  • 舉例:如Windows自帶的NTFS、FAT32、EXFAT,和Linux中的EXT3、EXT4這種的。
  • FAT32:有著很好的兼容性,但是不支持單個大于4GB的文件,U盤空間充足卻放不下大文件,就是這個原因。可以格式化后換一個文件系統解決。
  • NTFS:NTFS是Windows操作系統中最常用的文件系統之一,它支持大容量硬盤和大文件,提供了較好的安全性、穩定性和恢復能力。
  • EXFAT:為了解決FAT32不支持單個大于4GB的文件而誕生。

操作系統的引導

  • 概括:操作系統的引導(Bootstrapping)是指在計算機啟動時,通過加載操作系統的核心組件和必要的驅動程序,使得計算機能夠進入操作系統的運行狀態。引導過程通常包括以下幾個步驟:
  1. 加電自檢(Power-On Self-Test,POST):計算機啟動時,會執行自檢程序,檢查硬件是否正常。如果自檢過程中發現硬件故障,計算機可能會發出警報或者停止啟動。
  2. BIOS/UEFI初始化:計算機啟動后,會加載基本輸入/輸出系統(Basic Input/Output System,BIOS)或統一可擴展固件接口(Unified Extensible Firmware Interface,UEFI),進行硬件初始化和系統設置。
  3. 引導加載程序(Bootloader)啟動:BIOS/UEFI會尋找引導加載程序,一般位于硬盤的引導扇區(Boot Sector)或其他可引導的介質(如USB閃存驅動器)。引導加載程序的主要任務是加載操作系統的內核鏡像到內存中,并執行操作系統的初始化。
  4. 內核初始化:一旦操作系統的內核鏡像被加載到內存中,引導加載程序將控制權轉交給操作系統內核。內核開始初始化系統的各個部分,包括設備驅動程序、文件系統等。
  5. 用戶空間初始化:內核完成初始化后,操作系統開始啟動用戶空間的進程,包括系統服務和用戶登錄界面。

聯合文件系統UnionFileSystem

聯合文件系統(UFS),是一種分層的高性能文件系統,支持對文件系統的修改作為一次提交來層層疊加。
docker用它作為鏡像的存儲方式,使得容器在運行時只需存儲修改過的部分,而不是整個文件系統,從而節省存儲空間并提高效率。

為什么docker用UFS

  • 共享和復用:UFS 允許多個容器共享相同的基礎鏡像層,這樣可以節省存儲空間,并減少容器的創建和啟動時間。當多個容器共享相同的文件系統層時,這些層中的文件和資源只需存儲一次,而不是每個容器都存儲一份。這和代碼是一樣的,封裝的方法拆分的越小,可復用性就會更好。
  • 寫時復制(Copy-on-Write):UFS 允許容器在運行時進行讀寫操作,同時保留了鏡像的不可變性。當容器對文件系統進行修改時,UFS 會將修改的內容寫入新的層中,而不會直接修改原始鏡像層,這樣可以確保容器之間的隔離性,并且不會影響其他容器或原始鏡像。
  • 快速啟動和部署:由于 UFS 允許容器共享文件系統層并利用寫時復制機制,因此容器的創建和啟動速度非常快。Docker 可以快速地在現有鏡像的基礎上創建新的容器實例,并立即啟動運行,這對于實現快速部署和橫向擴展至關重要。
  • 輕量級:UFS 提供了一種輕量級的文件系統封裝方式,它不需要完整地復制整個文件系統,而是在需要修改文件時才進行復制和修改,這樣可以節省存儲空間并減少資源消耗,下文會講。

深入理解Docker鏡像分層加載原理

  • 簡易概括:在BootFS(宿主機提供)的基礎上,利用UFS封裝RootFS,使用鏡像層的數據,疊加出一個可寫的容器層。
    所以說,docker pull下來的CentOS、Ubuntu發行版,才很小,一個原因是省掉了BootFS,另一個原因是拋棄了很多非核心的組件,如vim等。


  • BootFS:引導文件系統(boot filesystem)是指用于引導操作系統的文件系統。這個文件系統通常包含了引導加載程序(boot loader)所需的文件,例如引導配置文件、內核以及其他引導所需的文件,docker用宿主機的內核,出處就是這里。

  • RootFS:在 Linux 中,rootfs(root file system)是指操作系統啟動后的根文件系統,它包含了整個文件系統的目錄結構和文件,提供了用戶空間程序運行所需的基本文件和資源,例如根目錄下的幾個目錄。

  • 鏡像層:只讀的,包含了應用程序運行所需的所有文件和依賴項。

  • 容器層:可寫的,當容器啟動時,一個新的容器層被加載到容器的頂部,用來支撐數據變化的存儲。

上下層級關系是這樣的:
docker的UFS管理了最上面的3層,利用寫時復制(Copy-on-Write)的機制,當容器需要修改文件時,UFS 會在容器層中進行寫操作,而不會直接修改鏡像層中的文件。這樣可以保證鏡像的不可變性,同時允許容器進行靈活的讀寫操作。
新的容器又可以commit成一個新的鏡像,這個新的鏡像基礎上,又可以堆疊更多的容器,層層累加。

              --容器層--
           -----鏡像層------
      ----------RootFS----------
----------------BootFS----------------

容器數據卷

  • 極簡概括:容器數據卷,容器卷、數據卷、一個概念,將宿主機中的目錄或文件掛載到容器中,從而讓容器和宿主機共同讀寫這塊的數據。并且在容器銷毀時,容器卷的數據不會丟失。
  • 用法:docker run --name name1 [-it/-d] -v /宿主機絕對路徑:/容器內絕對路徑 --privileged=true 鏡像id [/bin/bash]
  • 備注:-v是volume的首字母,掛載目錄默認是讀寫權限,但是目錄本身容器內部刪不掉(極少需要刪除),如果宿主機沒有這個目錄,只要權限充足,它會自動創建。
  • 適用場景:
    • 數據備份:當容器被誤刪,或者容器內的組件因故障無法運行時,容器卷的數據保留的好好的,這算是一種容災。
    • 數據互通:容器內的組件,和容器外的系統,可以共享這塊數據的讀寫,實時的,這對開發者、運維人員很友好。
    • 同步日志和數據:很多組件,應用、日志、數據是可以分開的,所以就可以把日志,數據,放進多個數據卷。
  • 優點:
    • 上文的適用場景,就是兩個優點。
    • 易于備份:通過使用容器卷,可以輕松地備份和恢復數據,而不需要備份整個容器。
  • 缺點:
    • 復雜化:對于新手,或者剛接觸新服務器的運維人員,多容器下的容器卷管理,使得運維工作錯綜復雜。
    • 高可用問題:MySQL不推薦在docker中,其中一個就是數據的高可用問題,MySQL減少保障故障時數據丟失問題和維護高可用帶來的性能問題,使用了3種不同的redo log刷盤機制作為保障,但是又加了一個容器卷環節,多了一個環節,就有可能在這上面出故障,尤其是MySQL這種需要環境極度穩定的組件。

使用容器卷記得添加--privileged=true

使容器具有完全可控的權限,防止出現Permission denied的錯誤。
注意是等號,不是空格,有個d。

容器數據卷實操

對數據同步的測試

docker run --name=zs_ubuntu --privileged=true -it -v /test:/test b3797fa08f5b /bin/bash
進入ubuntu容器后
cd /test
touch a
開啟另一個宿主機終端
touch b
容器和宿主機互相ls,發現都有a、b兩個文件

使用inspect命令查看掛載相關配置

docker inspect 容器id
找到Mounts段,
"Mounts": [
    {
        "Type": "bind",
        "Source": "/test",
        "Destination": "/test",
        "Mode": "",
        "RW": true,
        "Propagation": "rprivate"
    }
],


Type: 指定了數據卷的類型,這里是bind,表示這是一個綁定掛載,即將宿主機上的一個目錄掛載到容器內部。
Source: 指定了數據卷的來源,這里是/test,表示宿主機上的目錄路徑。
Destination: 指定了數據卷在容器內的掛載目標路徑,這里也是/test,表示容器內部的路徑。
Mode: 這個字段可以用來指定掛載的權限模式,但在這個配置中為空,表示使用默認權限。
RW: 表示是否以讀寫模式掛載,這里是true,表示掛載為讀寫模式。
Propagation: 指定了掛載點的傳播屬性,這里是rprivate,表示掛載點將會被私有化傳播,即只會影響到當前容器的進程,不會傳播到其他容器。

故障情況下,容器卷內容的情況

停止容器
docker stop ea03c5ef1025
在宿主機內,創建文件
touch /test/c
開啟
docker start ea03c5ef1025
進入容器
docker exec -it ea03c5ef1025 /bin/bash
此時發現c依舊存在
ls /test


宿主機誤刪容器(強制)
docker rm -f ea03c5ef1025
發現a、b、c3個文件都在。
ls /
重新創建新的容器
docker run --name=zs_ubuntu --privileged=true -it -v /test:/test b3797fa08f5b /bin/bash
進入容器后,發現a、b、c 3個文件都在。
ls /

容器數據卷的rw與ro兩種讀寫權限

rw:默認值,雙方各有讀寫權限。

執-v命令時,默認是讀寫權限,以下兩個命令是相等的。
docker run --name=zs_ubuntu --privileged=true -it -v /test:/test b3797fa08f5b /bin/bash
docker run --name=zs_ubuntu --privileged=true -it -v /test:/test:rw b3797fa08f5b /bin/bash

ro:宿主機的文件可以同步給容器,但容器無法更改。

某些情況下,需要將宿主機映射的目錄,讓容器只有只讀權限,read only,可以這樣做:
docker run --name=zs_ubuntu --privileged=true -it -v /test:/test:ro b3797fa08f5b /bin/bash

進入容器,測試容器內寫入
touch /test/d
touch: cannot touch 'd': Read-only file system

進入宿主機終端,測試文件寫入:
touch /test/d
宿主機成功寫入

進入容器,查看容器是否同步,發現已經同步
ls /test/d
a  b  c  d

容器數據卷的繼承

卷的繼承需要“--volumes-from 父容器卷” 來聲明,具有父子關系的容器卷還是互相共享關系,父子間并沒有強關聯,意味著父容器停了或被刪除,不影響子容器。

請空容器,方便測試。
docker rm -f 4432fa5f2d07
并刪除/test下所有文件
rm -f /test/*
啟動一個父容器
docker run --name parent --privileged=true -it -v /test:/test b3797fa08f5b /bin/bash
啟動一個子容器
docker run --name son --privileged=true -it --volumes-from parent b3797fa08f5b /bin/bash
宿主機查看正在運行的容器實例
docker ps -a
CONTAINER ID   IMAGE          COMMAND       CREATED         STATUS         PORTS     NAMES
5ff477d6b3ec   b3797fa08f5b   "/bin/bash"   5 minutes ago   Up 4 minutes             son
a4da63aca520   b3797fa08f5b   "/bin/bash"   6 minutes ago   Up 6 minutes             parent

宿主機創建a文件
touch /test/a
兩個容器上查看,發現a文件都存在。
touch /test

父級故障模擬,測試父子關聯性,結果得出父子間沒有強關聯性。

在宿主機上停止父級容器
docker stop a4da63aca520
在宿主機上創建文件
touch /test/b
在son容器上執行ls,發現有a、b兩個文件
ls /test
a b


在宿主機上刪除父級容器
docker rm a4da63aca520
在宿主機上創建文件
touch /test/c
在son容器上執行ls,發現有a、b、c兩個文件
ls /test
a b c

容器卷的多樣化共享

多容用一卷:

強制刪除所有容器,能不用則不用。
docker rm -f $(docker ps -aq)
刪除宿主機下,容器卷目錄所有文件
rm -f /test/*

開3個終端,創建3個容器
docker run --name one --privileged=true -it -v /test:/test b3797fa08f5b /bin/bash
docker run --name two --privileged=true -it -v /test:/test b3797fa08f5b /bin/bash
docker run --name three --privileged=true -it -v /test:/test b3797fa08f5b /bin/bash

查看是否開啟成功
docker ps
CONTAINER ID   IMAGE          COMMAND       CREATED          STATUS          PORTS     NAMES
8ed7a2356d5c   b3797fa08f5b   "/bin/bash"   17 seconds ago   Up 10 seconds             three
ff2b2a92d984   b3797fa08f5b   "/bin/bash"   26 seconds ago   Up 25 seconds             two
220539fdf650   b3797fa08f5b   "/bin/bash"   54 seconds ago   Up 53 seconds             one

宿主機創建a文件
touch /test/a

三個容器分別執行ls /test,發現都有a
ls /teset
a

一容用多卷:

強制刪除所有容器,能不用則不用。
docker rm -f $(docker ps -aq)
刪除宿主機下,容器卷目錄所有文件
rm -f /test/*
并額外創建2個目錄
touch /test2 /test3
如下
ll / | grep test
drwxr-xr-x.   2 root root    6 4月  12 03:07 test
drwxr-xr-x    2 root root    6 4月  12 03:07 test2
drwxr-xr-x    2 root root    6 4月  12 03:07 test3

創建一個容器,并映射3個目錄
docker run --name test --privileged=true -it -v /test:/test -v /test2:/test2 -v /test3:/test3 b3797fa08f5b /bin/bash
發現容器內也有3個目錄
ll / | grep test
drwxr-xr-x.   2 root root    6 Apr 11 19:07 test/
drwxr-xr-x    2 root root    6 Apr 11 19:07 test2/
drwxr-xr-x    2 root root    6 Apr 11 19:07 test3/

容器內執行
touch /test/a /test2/a /test3/a
宿主機查看,發現文件依然共享
ls /test /test2 /test3
/test:
a

/test2:
a

/test3:
a

網卡相關

安裝docker后,執行ifconfig,會看到以下內容:

  • ens33(老版本的叫eth0)是配置宿主機網絡用的。
  • lo是本地回環地址,用于本地主機內部通信的虛擬網絡接口。
  • docker就是安裝docker時虛擬出來的網卡,用于docker容器間和宿主機的通信:
    • flags=4099<UP,BROADCAST,MULTICAST> mtu 1500: 這部分顯示了網絡接口的名稱(docker0)、標志和 MTU(最大傳輸單元)值(1500)。
    • inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255: 這部分顯示了網絡接口的 IPv4 地址(172.17.0.1)、子網掩碼(255.255.0.0)和廣播地址(172.17.255.255)。這個地址范圍是 Docker 橋接網絡的默認范圍。
    • inet6 fe80::42:37ff:fef9:25d7 prefixlen 64 scopeid 0x20<link>: 這部分顯示了網絡接口的 IPv6 地址。
    • ether 02:42:37:f9:25:d7 txqueuelen 0 (Ethernet): 這部分顯示了網絡接口的 MAC 地址和一些其他信息。
    • RX packets 4197 bytes 250537 (244.6 KiB): 這部分顯示了接收到的數據包和字節數。
    • TX packets 4317 bytes 14144344 (13.4 MiB): 這部分顯示了發送的數據包和字節數。。
ifconfig

docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:37ff:fef9:25d7  prefixlen 64  scopeid 0x20<link>
        ether 02:42:37:f9:25:d7  txqueuelen 0  (Ethernet)
        RX packets 4197  bytes 250537 (244.6 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 4317  bytes 14144344 (13.4 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.180  netmask 255.255.255.0  broadcast 192.168.0.255
        inet6 fe80::2545:6607:f0f7:64cb  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:39:be:95  txqueuelen 1000  (Ethernet)
        RX packets 20615  bytes 15431772 (14.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 10726  bytes 954390 (932.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 32  bytes 2592 (2.5 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 32  bytes 2592 (2.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

執行ip a,也會看到類似的內容:

  • <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default: 這部分顯示了網絡接口的名稱(docker0)、狀態(DOWN)、標志(NO-CARRIER、BROADCAST、MULTICAST、UP)、MTU(最大傳輸單元)值(1500)以及隊列規則(qdisc)等信息。
  • link/ether 02:42:37:f9:25:d7 brd ff:ff:ff:ff:ff:ff: 這部分顯示了網絡接口的 MAC 地址和廣播地址。
  • inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever: 這部分顯示了網絡接口的 IPv4 地址(172.17.0.1)、子網掩碼(/16),以及廣播地址。valid_lft和 `preferred_lft 分別表示地址的有效生存時間和首選生存時間,設置為 forever 表示永久有效。
  • inet6 fe80::42:37ff:fef9:25d7/64 scope link valid_lft forever preferred_lft forever: 這部分顯示了網絡接口的 IPv6 地址和范圍。
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
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:39:be:95 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.180/24 brd 192.168.0.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::2545:6607:f0f7:64cb/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:37:f9:25:d7 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:37ff:fef9:25d7/64 scope link 
       valid_lft forever preferred_lft forever

Docker網絡

docker網絡顧名思義,為什么要去研究它?

  • 控制容器間通信:只有容器不通信,好比買了個手機不聯網,技能無法充分發揮。
  • 降低對網絡的運維成本:容器IP變動時(增加、減少容器數量等因素),可以通過服務名進行通信,保證通信不受影響。

Docker網絡相關命令

在docker run時,可以使用docker run --network bridge ...去指定驅動程序。

docker network ls

NETWORK ID     NAME      DRIVER    SCOPE
f4481eb7078e   bridge    bridge    local
c10b6f388063   host      host      local
21c306a93cbb   none      null      local
  • NETWORK ID:網絡唯一標識。
  • NAME:起個名。
  • DRIVER:Docker 網絡所使用的驅動程序,一些常見的網絡驅動程序包括:
    • bridge(橋接 默認值): 默認的 Docker 網絡驅動程序,使用docker0網卡連接容器到宿主機的網絡。
    • host(主機): 讓容器直接使用宿主機的網絡命名空間,與宿主機共享網絡棧,使用這個,docker run -p就沒有意義了。
    • overlay(覆蓋): 允許在多個 Docker 宿主機上創建連接的容器網絡,用于容器在不同宿主機間通信。
    • macvlan(MACVLAN): 允許容器擁有自己的 MAC 地址,并直接與物理網絡相連。
    • none(無): 禁用容器的網絡,使容器無法進行網絡通信,很少用。
    • container(容器):新創建的容器不會創建自己的網卡,而是和一個指定容器共享IP和端口,很少用,容易端口沖突,且對容器有依賴性。
  • SCOPE:定義網絡范圍的作用域
    • local(本地 默認值): 這表示網絡只在當前 Docker 宿主機上可見和可用,不會跨越宿主機邊界。
    • global(全局): 這表示網絡在所有 Docker 宿主機上都可見和可用,可以跨越宿主機邊界。
    • swarm(集群): 這表示網絡是 Docker Swarm 集群中的一部分,可以在整個 Swarm 集群中使用。

Docker對網絡配置的增刪改查操作:

執行網絡聯機的命令行幫助,會得到以下內容,無外乎就是增刪改查
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.


增:
docker network create test_net
7b7c0cbc15c65a5ef4a0e1ad5e7d997ec04afb322afc9e67845c8735ccf1fb06
docker network ls
NETWORK ID     NAME       DRIVER    SCOPE
f4481eb7078e   bridge     bridge    local
c10b6f388063   host       host      local
21c306a93cbb   none       null      local
7b7c0cbc15c6   test_net   bridge    local

刪:
docker network rm test_net
^[[Atest_net
docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
f4481eb7078e   bridge    bridge    local
c10b6f388063   host      host      local
21c306a93cbb   none      null      local

改:極少操作。

查:
docker inspect f4481eb7078e
返回一個json。

Docker網絡通信架構

  • docker0:虛擬出來一塊網卡,讓容器之間、宿主機、進行通信。docker0是虛擬出來的硬件,bridge是通信的方式。
  • veth:veth(Virtual Ethernet)是Linux系統中一種虛擬網絡設備,常用于 Docker 容器之間和容器與宿主機之間的通信,當創建一個Docker容器時,Docker會為容器分配一個唯一的網絡命名空間,并為該容器創建一個veth pair設備。容器內的veth設備稱為 eth0(或其他指定的網絡接口名),而與之配對的宿主機端的veth設備可以在宿主機上看到,通常以 vethXXX 這樣的形式命名。通過這種方式,容器可以通過自己的網絡接口與宿主機上的其他容器或外部網絡進行通信。Docker 使用 Linux 的網絡命名空間和 veth 設備來隔離容器的網絡棧,同時通過網絡橋接(如 docker0)實現容器與宿主機網絡的連接和通信。
  • eth0:這是每個容器實例或宿主機自身的內部網卡。
  • 注意:容器內的eth0和veth總是成雙成對的出現。
  • 通信方式:無論是容器與容器之間,容器與宿主機之間,都需要通過docker0的bridge方式通信。

上一張經典的圖:


78ca3cb36a5648be91429bf85ce88759.png

開兩個Nginx證明一下是否是多出來兩個veth:

關閉宿主機nginx服務,nginx設置開啟了服務
service nginx stop
起兩個nginx容器
docker run -d -p 80:80 nginx
docker run -d -p 8080:80 nginx
確定容器是否真的跑起來
docker ps
CONTAINER ID   IMAGE     COMMAND                   CREATED         STATUS         PORTS                                   NAMES
bf6321d659c4   nginx     "/docker-entrypoint.…"   2 minutes ago   Up 2 minutes   0.0.0.0:8080->80/tcp, :::8080->80/tcp   funny_williams
859b85ccf760   nginx     "/docker-entrypoint.…"   2 minutes ago   Up 2 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp       brave_vaughan

確定配置是否成功,或用curl訪問也行
netstat -nlp | grep 80
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      22982/docker-proxy  
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      22838/docker-proxy  
tcp6       0      0 :::8080                 :::*                    LISTEN      22988/docker-proxy  
tcp6       0      0 :::80                   :::*                    LISTEN      22844/docker-proxy  
unix  2      [ ACC ]     STREAM     LISTENING     50191    6480/abrtd           /var/run/abrt/abrt.socket


重點來了,然后再執行ifconfig,會發現多出來兩個veth開頭的網卡:
ifconfig

veth7c2861b: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::e881:5aff:fe82:55ca  prefixlen 64  scopeid 0x20<link>
        ether ea:81:5a:82:55:ca  txqueuelen 0  (Ethernet)
        RX packets 35  bytes 4797 (4.6 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 52  bytes 7096 (6.9 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

veth8ed54b8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::1cb3:6eff:fe84:1563  prefixlen 64  scopeid 0x20<link>
        ether 1e:b3:6e:84:15:63  txqueuelen 0  (Ethernet)
        RX packets 31  bytes 4017 (3.9 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 37  bytes 4395 (4.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

同理,可以使用ip a命令
ip addr

14: veth7c2861b@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether ea:81:5a:82:55:ca brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::e881:5aff:fe82:55ca/64 scope link 
       valid_lft forever preferred_lft forever
18: veth8ed54b8@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 1e:b3:6e:84:15:63 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::1cb3:6eff:fe84:1563/64 scope link 
       valid_lft forever preferred_lft forever

想要驗證,與eth0是否是成對出現的,但是nginx鏡像缺少ip 或者ifconfig命令,apt-get update命令報錯,導致無法驗證。
實際上宿主機上看的veth7c2861b@if13和veth8ed54b8@if17中的if13與if17,都是與容器當中的網卡編號對應的。

當使用docker inspect 容器id時,就能看到該容器網絡相關的信息。

docker inspect 6dc7f1d29a17 | tail -n 21
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "",
                    "NetworkID": "f4481eb7078ebf9be90119f8a99f5869354ed14d9b093924da43bf1ba19b36a0",
                    "EndpointID": "",
                    "Gateway": "",
                    "IPAddress": "",
                    "IPPrefixLen": 0,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DriverOpts": null,
                    "DNSNames": null
                }
            }

對于這個json,做個介紹:

  • "IPAMConfig": 這是用于管理IP地址的配置,通常在Docker網絡模式為bridge時使用。
  • "Links": 這里是容器與其他容器之間鏈接的信息,但在這個例子中為null,表示沒有其他容器鏈接到這個容器。
  • "Aliases": 這是容器的網絡別名,也是null,表示沒有設置別名。
  • "MacAddress": 這是容器的MAC地址,通常由Docker自動生成。
  • "NetworkID": 這是網絡的唯一標識符,用于區分不同的Docker網絡。
  • "EndpointID": 這是容器端點的唯一標識符,用于標識容器在網絡中的位置。
  • "Gateway": 這是網絡的網關地址,通常由Docker提供。
  • "IPAddress": 這是容器分配的IP地址。
  • "IPPrefixLen": 這是容器IP地址的前綴長度,通常是一個整數。
  • "IPv6Gateway": 這是IPv6網絡的網關地址。
  • "GlobalIPv6Address": 這是容器的全局IPv6地址。
  • "GlobalIPv6PrefixLen": 這是容器的全局IPv6地址的前綴長度。
  • "DriverOpts": 這是網絡驅動的選項配置,通常在特定網絡驅動中使用。
  • "DNSNames": 這是容器的DNS名稱列表,用于解析容器內部的 DNS 查詢。

不同容器配置不同的Docker網絡

  • 為了分門別類,方便管理。
  • 有了它,可以避免IP變動引起的故障,為docker容器編排做準備。
創建網絡
docker network create zs_test
ee465a9eccd7d758e3b4a4281539352d8169364f860091928f3296129c6ac384

并查看
docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
f4481eb7078e   bridge    bridge    local
c10b6f388063   host      host      local
21c306a93cbb   none      null      local
ee465a9eccd7   zs_test   bridge    local

開兩個終端分別執行
docker run --name centos01 --network zs_test -it 5d0da3dc9764 /bin/bash
docker run --name centos02 --network zs_test -it 5d0da3dc9764 /bin/bash

然后再任意終端上ping另一個容器的name參數
ping centos02
PING centos02 (172.23.0.3) 56(84) bytes of data.
64 bytes from centos02.zs_test (172.23.0.3): icmp_seq=1 ttl=64 time=0.082 ms
64 bytes from centos02.zs_test (172.23.0.3): icmp_seq=2 ttl=64 time=0.095 ms
64 bytes from centos02.zs_test (172.23.0.3): icmp_seq=3 ttl=64 time=0.090 ms

使用name參數,可以避免IP變動情況的發生。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容