第一節:容器通信技術
一:Docker 容器的網絡模式
? ? ? 當項目大規模使用 Docker 時,容器通信的問題也就產生了。要解決容器通信問題,必須先了解很多關于網絡的知識。Docker 的網絡模式非常豐富,可以滿足不同容器的通信要求,下表列出了這些網絡模式的主要信息。
網絡模式 | 創建此種網絡模式的關鍵選項 | 簡單說明 |
---|---|---|
host 模式 | --network host | 容器直接使用宿主主機的網絡棧,沒有獨立的網絡命名空間,網絡性能高,但容器與宿主主機共享網絡資源,易出現端口沖突。 |
container 模式 | --network container:<已存容器名或 ID> | 新容器共享指定已有容器的網絡命名空間,兩個容器網絡配置相同,適用于需要緊密耦合通信的容器組合。 |
none 模式 | --network none | 容器僅有一個 lo 回環接口,無任何外部網絡連接,適用于對網絡安全性要求極高或需手動配置網絡的場景。 |
bridge 模式 | 默認模式,可通過 -d bridge 手動指定(一般省略) | Docker 默認網絡模式,創建 docker0 虛擬網橋,容器通過 veth 設備連到該網橋;容器有獨立 IP,借助宿主主機 NAT 訪問外部網絡。 |
Overlay 模式 | -d overlay | 用于 Docker Swarm 集群,基于 VXLAN 技術創建跨主機的虛擬覆蓋網絡,實現不同宿主主機上容器間的通信。 |
macvlan 模式 | -d macvlan,還需指定 --subnet、--gateway 和 -o parent=<宿主機構物理網卡> | 為容器分配唯一 MAC 地址,使其像獨立物理設備,直接連接宿主機構物理網絡接口,繞過 docker0 網橋,提高網絡性能。 |
自定義網絡模式 | docker network create 結合如 --subnet、--gateway、--ip-range 等參數 |
1: Bridge 模式
? ? ? 當 Docker 安裝完成后,會自動創建一個名為 docker0 的虛擬網橋。在 Bridge 模式下,新創建的容器會通過一個虛擬以太網設備對(veth pair)連接到 docker0 網橋上。
? ? ? Docker 守護進程會從預定義的子網中為每個容器分配一個唯一的 IP 地址。容器可以通過 docker0 網橋與宿主主機以及其他連接到該網橋的容器進行通信。
? ? ? 當容器需要訪問外部網絡時,宿主主機的內核會通過網絡地址轉換(NAT)將容器的私有 IP 地址轉換為宿主主機的公共 IP 地址,從而實現容器與外部網絡的通信。
? ? ? bridge 模式是 docker 的默認網絡模式,不寫 -net 參數,就是 bridge 模式。使用 docker run -p 時,docker 實際是在 iptables 做了 DNAT 規則,實現端口轉發功能。可以使用 iptables -t nat -vnL 查看。
? ? ? 如果你之前有 Docker 使用經驗,你可能已經習慣了使用 --link 參數來使容器互聯。
? ? ? 隨著 Docker 網絡的完善,強烈建議大家將容器加入自定義的 Docker 網絡來連接多個容器,而不是使用 --link 參數。
(1)創建一個叫 my - net 的 bridge 類型的網絡
docker network create -d bridge my - net
(2)查看都有哪些網絡
docker network ls
(3)運行一個容器并連接到新建的 my - net 網絡
docker run -dit --name busybox1 --rm --network my-net busybox sh -c "while true;do echo nihao;done"
(4)運行一個容器并加入到 my - net 網絡
docker run -it --name busybox2 --rm --network my-net busybox sh
2: Host 模式
? ? ? 使用 Host 模式的容器會直接使用宿主主機的網絡棧,容器沒有獨立的網絡命名空間,而是與宿主主機共享相同的 IP 地址、端口等網絡資源。
? ? ? 由于容器和宿主主機共享網絡棧,因此容器可以直接使用宿主主機的網絡接口,不存在網絡地址轉換和網橋轉發的開銷,網絡性能較高。但同時也意味著容器之間以及容器與宿主主機之間的網絡隔離性較差,可能會出現端口沖突等問題。
? ? ? 如果啟動容器的時候使用 host 模式,那么這個容器將不會獲得一個獨立的 Network Namespace,而是和宿主主機共用一個 Network Namespace。容器將不會虛擬出自己的網卡,配置自己的 IP 等,而是使用宿主主機的 IP 和端口。但是,容器的其他方面,如文件系統、進程列表等還是和宿主主機隔離的。Host
docker run -dit --net=host --name docker_nost1 busybox
? ? ? 由于使用了 Host 模式,容器會直接使用宿主主機的網絡端口,因此可以直接在宿主主機上通過?localhost?訪問容器內的服務,使用 ifconfig 命令可以看到容器的網絡和宿主的是一致的。
docker exec -it docker_host1 sh
3: Container 模式
? ? ? Container 模式允許一個容器共享另一個容器的網絡命名空間,即兩個容器使用相同的網絡配置,包括 IP 地址、端口等,利用這種模式使得容器共享統一的網絡命名空間。
? ? ? 這種模式適用于那些需要緊密耦合的容器,例如一個應用程序和它的日志收集器容器,它們可以共享同一個網絡,方便進行通信和數據傳輸。
? ? ? 這個模式指定新創建的容器和已經存在的一個容器共享一個 Network Namespace,而不是和宿主主機共享。新創建的容器不會創建自己的網卡,配置自己的 IP,而是和一個指定的容器共享 IP、端口范圍等。同樣,兩個容器除了網絡方面,其他的如文件系統、進程列表等還是隔離的。兩個容器的進程可以通過 lo 網卡設備通信。
docker run -tid --name host1 busybox
(1)創建 host2 容器共享 host1 容器的網絡
docker run -itd --net = container:host1 --name host2 busybox
(2)查詢 host1 容器的網絡
docker exec -it host1 ifconfig
(3)查詢 host2 容器的網絡,確認和 host1 容器的網絡一致
docker exec -it host2 ifconfig
4: None 模式
? ? ? 在 None 模式下,容器只有一個 lo 回環接口,沒有任何外部網絡連接。這種模式適用于那些不需要網絡通信或者需要手動配置網絡的場景,例如某些安全敏感的應用程序。
? ? ?如果需要為 None 模式的容器添加網絡功能,需要手動創建網絡接口并進行配置。
? ? ? 使用 none 模式,Docker 容器擁有自己的 Network Namespace,但是,并不為 Docker 容器進行任何網絡配置。也就是說,這個 Docker 容器沒有網卡、IP、路由等信息。需要我們自己為 Docker 容器添加網卡、配置 IP 等。
docker run -itd --net = none --name none01 busybox sh
docker exec -it none01 sh
5: Overlay 模式
? ? ? Overlay 模式主要用于 Docker Swarm 集群,它允許容器在不同的 Docker 宿主主機之間進行通信。它基于 VXLAN(Virtual eXtensible Local Area Network)技術,在物理網絡之上創建一個虛擬的覆蓋網絡。
? ? ? 當容器之間進行通信時,數據包會被封裝在 VXLAN 報頭中,通過物理網絡進行傳輸。在接收端,VXLAN 報頭會被解封裝,還原出原始的數據包。
? ? ? Overlay 網絡是分布式的,每個 Docker 宿主主機上都有一個網絡代理(如 Docker 的docker_gwbridge)負責管理和轉發數據包。
示例:
# 在 Docker Swarm 集群中創建一個 Overlay 網絡
docker network create -d overlay my_overlay_network# 在不同的宿主主機上創建服務并連接到 Overlay 網絡
docker service create --name my_service --network my_overlay_network nginx
6: Macvlan 模式
? ? ?在 Macvlan 模式下,Docker 為每個容器分配一個唯一的 MAC 地址,使得容器在網絡中看起來像一個獨立的物理設備。
? ? ? 容器直接連接到宿主主機的物理網絡接口,繞過了 docker0 網橋,從而提高了網絡性能。容器可以直接與外部網絡進行通信,就像一個獨立的主機一樣。
每個容器都有自己獨立的網絡配置,與宿主主機和其他容器之間相互隔離。
示例:使容器獲得一個與宿主主機在同一子網內的 IP 地址,可以直接與外部網絡進行通信。
# 創建一個 Macvlan 網絡
docker network create -d macvlan \
--subnet = 192.168.1.0/24 \
--gateway = 192.168.1.1 \
-o parent = eth0 \
my_macvlan_network# 創建一個使用 Macvlan 網絡的容器
docker run -d --name my_macvlan_container --network my_macvlan_network nginx
7: 自定義網絡模式
? ? ? 除了上述內置的網絡模式,你還可以使用 docker network create 命令創建自定義的 bridge 網絡,以滿足特定的網絡需求,例如指定子網、網關、IP 范圍等。
示例 1:使用如下命令創建一個自定義網絡
docker network create \
--subnet = 172.21.0.0/16 \
--gateway = 172.21.0.1 \
my_custom_network
此命令的主要目的是創建一個新的 Docker 網絡,這個網絡可以用于容器之間的通信。默認情況下,創建的是一個基于 bridge 驅動的網絡。
- docker network create:這是 Docker 提供的用于創建網絡的基礎命令。
- --subnet = 172.21.0.0/16:指定了該網絡使用的子網范圍。172.21.0.0/16 是一個 CIDR(無類別域間路由)表示法,意味著該子網的網絡地址是 172.21.0.0,子網掩碼為 255.255.0.0,可以容納 65534 個可用的 IP 地址(2^16 - 2,減去網絡地址和廣播地址)。當容器連接到這個網絡時,它們將從這個子網范圍內分配 IP 地址。
- --gateway = 172.21.0.1:設置了該網絡的網關地址。網關是容器訪問外部網絡(超出該子網范圍)的出口點。當容器需要與子網外的網絡進行通信時,數據包會被發送到這個網關地址進行轉發。
- my_custom_network:為新創建的網絡指定了一個名稱,后續在創建容器時,可以通過這個名稱將容器連接到該網絡。
示例 2:創建一個新的容器并加入這個自定義網絡
docker run -d --name my_container --network my_custom_network nginx
二:端口映射
? ? ? Docker 是一個開源的容器化平臺,用于構建、運行和管理應用程序。它使用容器來打包應用程序及其依賴項,使得應用程序可以在不同的環境中快速、可靠地運行。在 Docker 中,端口映射是一個重要的特性,它允許容器內部的應用程序與宿主主機進行通信。
? ? ? Docker 的端口映射使用 -p 或 --publish 選項來實現。通過該選項,可以將容器內部的端口映射到宿主主機上的某個端口。這樣,容器內部的應用程序可以通過宿主主機的端口來訪問外部的網絡或服務。宿主主機上的端口號,表示容器內部的端口號。通過指定這兩個端口號,Docker 會將容器內部的端口映射到宿主主機的端口上。
1:端口映射
(1)-P(大寫):指的是容器應用 PORT 隨機映射到宿主主機上的 PORT
- 自動綁定所有對外提供服務的容器端口,映射的端口將會從沒有使用的端口池中自動隨機選擇,但是如果連續啟動多個容器的話,則下一個容器的端口默認是當前容器占用端口號 +1。
- 生產場景一般不使用隨機映射,好處是由 docker 分配,宿主主機端口不會沖突。
(2)-p(小寫):(宿主主機 PORT: 容器 PORT)
- 宿主主機 IP 不寫表示?
0.0.0.0
,宿主主機 PORT 不寫表示隨機端口,容器 PORT 必須指定,可以同時對多個端口進行映射綁定。 - 指定端口映射,在標準化場景下使用頻率高。
- 端口的取值范圍?
32768~61000
?之間
2:隨機映射的端口
? ? ? 在使用?docker run
?命令創建并啟動容器時,可以使用?-P
(大寫的 P)參數來實現隨機端口映射。它會將容器中?EXPOSE
?指令聲明的所有端口隨機映射到宿主主機的可用端口上。
假設你要運行一個 Nginx 容器,Nginx 默認監聽 80 端口。使用以下命令啟動容器:
docker run --rm -d -P nginx
docker ps -a
CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORTS | NAMES |
---|---|---|---|---|---|---|
bc9831ca1c0c | nginx | "/docker-entrypoint…" | 3 seconds ago | Up 2 seconds | 0.0.0.0:32768->80/tcp, :: :32768->80/tcp | naughty_haslett |
? ? ? 在?docker run --rm
?命令中,--rm
?是一個組合的選項,并不是?r
?和?m
?分別代表不同含義,它是一個整體參數,用于控制容器在停止運行后自動刪除。
? ? ?當你在運行容器時添加?--rm
?選項,Docker 會在容器退出時自動刪除該容器的文件系統和所有相關資源,這樣可以避免產生大量不再使用的容器,節省磁盤空間。
3:指定映射端口
? ?docker run
?命令用于創建并啟動一個新的容器,通過?-p
(小寫的 p)參數可以指定容器端口到宿主主機端口的映射。
(1)固定端口
假設你要運行一個 Nginx 容器,并將容器的 80 端口映射到宿主主機的 8080 端口,可使用以下命令:
docker run --rm -d -p 8080:80 nginx
需要注意的是,在映射端口時,所使用的 docker 主機上的端口不能與其他容器或程序的端口沖突。否則,容器無法正常創建。
(2)宿主主機隨機端口
當使用小寫的?-p
?參數時,你可以不指定宿主主機的具體端口,只給出容器端口,Docker 會自動將容器端口映射到宿主主機的一個隨機可用端口上。
docker run --rm -d -p 80 nginxdocker ps
CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORTS | NAMES |
---|---|---|---|---|---|---|
89b94e02ea1 | nginx | "/docker-entrypoint…" | 2 minutes ago | Up 2 minutes | 0.0.0.0:32769->80/tcp | amazing_banach |
873340e689 | nginx | "/docker-entrypoint…" | 2 minutes ago | Up 2 minutes | 0.0.0.0:32768->80/tcp | sleepy_merkle |
6dbc5dbd8ef4 | nginx | "/docker-entrypoint…" | 2 minutes ag |
三:容器互聯
? ? ? 在 Docker 環境中,每個容器默認情況下是相互隔離的,它們有自己獨立的網絡棧。容器互聯就是打破這種隔離,讓不同容器能夠識別彼此并進行網絡通信,就像它們處于同一個本地網絡中一樣。通過容器互聯,一個容器可以像訪問本地網絡中的其他設備一樣訪問另一個容器提供的服務,比如訪問另一個容器運行的數據庫、web 服務等。
1:使用?--link
?選項(已逐漸被棄用)
? ? ?在早期的 Docker 版本中,--link
?選項用于實現容器互聯。它允許一個容器通過別名來訪問另一個容器。接下來介紹其實現步驟。
(1)創建源容器
docker run -dit --name web01 centos:7
(2)創建接收容器
docker run -dit --name web02 --link web01:myweb01 centos:7
? ? ? 該命令的主要功能是基于?centos:7
?鏡像創建并啟動一個名為?web02
?的容器,同時使用?--link
?選項將這個新容器與名為?web01
?的容器進行連接,使?web02
?容器可以通過?web01
?這個別名訪問?web01
?容器的服務。
? --link web01:myweb01
?字段是一個用于容器互聯的選項,但需要注意的是,該選項在較新的 Docker 版本中已逐漸被棄用。它的作用是將?web02
?容器與名為?web01
?的容器進行連接,并為?web01
?容器設置一個別名?myweb01
。在?web02
?容器內部,可以通過這個別名來訪問?web01
?容器提供的服務。
(3)測試容器互聯
docker exec -it web02 /bin/bash
cat /etc/hostsping myweb01
四:容器間通信實現案例
? ? ? 由于?--link
?選項已逐漸被棄用,建議使用 Docker 網絡來實現容器互聯。docker network create
?是 Docker 提供的一個用于創建自定義網絡的命令。在 Docker 中,網絡用于容器之間的通信以及容器與外部世界的通信。
1:常用選項及解釋
(1)--driver, -d
該選項用于指定網絡使用的驅動程序,默認值是?bridge
。常見的驅動類型有:
bridge
:默認的網絡驅動,適用于在單個 Docker 宿主主機上創建的容器之間的通信。host
:使用宿主主機的網絡棧,容器直接使用宿主主機的網絡接口,不進行網絡隔離。overlay
:用于在多個 Docker 宿主主機之間創建跨主機的網絡,通常用于 Docker Swarm 集群。macvlan
:允許為容器分配一個 MAC 地址,使其在網絡中看起來像一個獨立的物理設備。
示例:創建一個使用?bridge
?驅動的網絡
docker network create -d bridge my_bridge_network
(2)--subnet
該選項用于指定網絡的子網,格式為 CIDR 表示法(如?192.168.0.0/16
)。
示例:創建一個指定子網的網絡:
docker network create --subnet=172.18.0.0/16 my_subnet_network
(3)--gateway
該選項用于指定網絡的網關 IP 地址。
示例:創建一個指定子網和網關的網絡
docker network create \
--subnet=172.19.0.0/16 \
--gateway=172.19.0.1 \
my_gateway_network
(4)--ip-range
該選項用于指定容器可以使用的 IP 地址范圍。
示例:創建一個指定子網、網關和 IP 范圍的網絡
docker network create \
--subnet=172.20.0.0/16 \
--gateway=172.20.0.1 \
--ip-range=172.20.1.0/24 \
my_ip_range_network
(5)--internal
該選項用于將網絡設置為內部網絡,即容器無法訪問外部網絡。
示例:創建一個內部網絡:
docker network create --internal my_internal_network
(6)--attachable
該選項可以允許獨立的容器(非服務容器)連接到這個網絡。
示例:創建一個可連接的網絡:
docker network create --attachable my_attachable_network
2:容器間通信步驟
(1)創建自定義網絡
docker network create my_net
(2)創建一個不在此自定義網絡的容器
docker run -dit --name web03 centos:7
(3)創建兩個容器,并加入自定義網絡
docker run -dit --name pc01 --net=my_net centos:7
docker run -dit --name pc02 --net=my_net centos:7
(4)登錄到容器,測試通信結果
docker exec -it pc01 /bin/bash
ping pc02 # 能通
ping web03 # 不能通
第二節:數據持久化技術
一:Docker 的數據管理
Docker 數據卷(Data Volumes)是 Docker 中用于持久化存儲數據的一種機制,它在容器和宿主主機之間建立了一種數據共享的方式,下面從多個方面詳細解釋 Docker 數據卷。
1:什么是數據卷
數據卷是一個可供一個或多個容器使用的特殊目錄,它繞過了容器的文件系統,直接將宿主主機上的目錄或文件掛載到容器內部。這意味著即使容器被刪除,數據卷中的數據也不會丟失,從而實現了數據的持久化存儲。
2:數據卷的作用
(1)數據持久化
容器的生命周期可能是短暫的,當容器被刪除時,其內部文件系統中的數據也會隨之消失。而數據卷可以將數據存儲在宿主主機上,確保數據不會因為容器的刪除而丟失。
(2)數據共享
多個容器可以同時掛載同一個數據卷,從而實現容器之間的數據共享。這對于需要共享配置文件、日志文件或其他數據的應用場景非常有用。
(3)數據備份和恢復
由于數據卷中的數據存儲在宿主主機上,因此可以方便地進行備份和恢復操作。
(4)分離數據和應用
將數據存儲在數據卷中,可以使容器的鏡像更加輕量化,只包含應用程序本身,而將數據分離出來,提高了容器的可移植性和可維護性。
2:創建匿名數據卷
在創建容器時,可以使用?-v
?或?--volume
?參數來創建和掛載匿名數據卷。
docker run -dit -v /data1 -v /data2 --name web04 centos:7
上述命令創建了一個名為?web04
?的容器,并在容器內部創建了一個?/data1
?目錄和?/data2
?目錄作為數據卷。Docker 會自動在宿主主機上的?/var/lib/docker/volumes
?目錄下分配一個該容器的目錄來存儲這個數據卷的數據。當把此容器刪除掉以后,宿主主機上的目錄以及里面的數據仍然存在。可登錄到此容器驗證這一效果。
[root@localhost ~]# docker exec -it web04 /bin/bash
[root@9a398d3ec1f3 /]# cd /data1
[root@9a398d3ec1f3 data1]# cd /data2
3:創建具名數據卷
具名數據卷是一種有名稱的數據卷,可以更方便地管理和使用。創建方法如下。
(1)創建具名數據卷
docker volume create my_volume
(2)在創建容器時掛載具名數據卷
docker run -d -v my_volume:/data --name my_container nginx
上述命令首先創建了一個名為?my_volume
?的具名數據卷,然后在創建容器時將該數據卷掛載到容器內部的?/data
?目錄。
4:共享容器數據卷
如果希望在容器之間共享數據,可以使用下面的命令來實現。
[root@localhost ~]# docker run -dit --volumes-from web04 --name web05 centos:7 /bin/bash
這個命令的主要功能是基于?centos:7
?鏡像創建并啟動一個名為?web05
?的新容器,該容器會以交互模式、守護進程模式運行,并且會從?web04
?容器中掛載所有的數據卷。
--volumes-from web04
:這是一個關鍵參數,它的作用是讓新創建的?web05
?容器掛載?web04
?容器中所有已經掛載的數據卷。這意味著?web05
?容器可以訪問和使用?web04
?容器所使用的數據卷中的數據,實現數據的共享。
注意事項:
- 如果?
web04
?容器被刪除,只要數據卷本身沒有被刪除,web05
?容器仍然可以正常訪問數據卷中的數據。 - 當多個容器共享同一個數據卷時,對數據卷中數據的修改會影響到所有掛載該數據卷的容器。
5:掛載主機目錄作為數據卷
可以將宿主主機上的指定目錄掛載到容器內部,實現數據的共享。
案例 1:
(1)將宿主主機上的?/data1
?目錄掛載到容器內的?/usr/local/apache2/htdocs
?目錄。
docker run -dit -p 8080:80 -v /data1:/usr/local/apache2/htdocs --name web06 httpd
(2)創建測試文件
echo "hi" > /data1/index.html
(3)訪問服務
curl 192.168.10.101:8080
案例 2:
利用數據卷掛載的方式,也可以實現文件掛載,以及多目錄同時掛載。需要注意的是,在對文件進行掛載的時候,宿主主機一定要提前準備好這個文件,否則,會在宿主主機上創建出一個以該文件名來命名的目錄。這樣,在容器中就無法使用這個文件了。
(1)在宿主主機創建掛載目錄
mkdir -p /www/{conf,html}
(2)準備數據
將編輯好的 nginx 配置文件拷貝到?/www/conf
將網站代碼拷貝到?/www/html
(3)創建容器
docker run -d -p 9090:80 \
-v /www/conf/nginx.conf:/etc/nginx/nginx.conf \
-v /www/html:/www/html \
-v /www/nginx/log:/var/log/nginx \
--name web08 nginx "nginx"
二:Docker 數據管理注意事項
? ? ? 在 Docker 中進行數據管理時,需要考慮數據的持久化、共享、備份、恢復以及安全性等多個方面。
1:明確使用場景選擇類型
- 匿名數據卷:創建簡單,但管理不便,適合臨時存儲中間數據。例如在構建過程中存儲臨時編譯文件。
- 具名數據卷:便于管理和共享,適用于需要持久化存儲且后續會頻繁使用的數據,如數據庫數據。
- 掛載主機目錄:方便與主機進行數據交互,適合需要與主機共享配置文件或數據的場景。
2:使用正確的路徑
掛載主機目錄作為數據卷時,必須使用絕對路徑,否則會導致掛載失敗。
3:數據卷清理
定期清理無用數據卷:使用?docker volume ls
?查看所有數據卷。對于不再使用的匿名或具名數據卷,使用?docker volume rm
?命令進行清理,避免占用過多磁盤空間。
4:容器內數據持久化
? ? ? 容器的文件系統是基于鏡像層和容器層構建的,容器層的數據在容器刪除時會丟失。因此,對于需要持久化的數據,應使用數據卷進行存儲。
? ? ? 多個容器可以掛載同一個數據卷來實現數據共享。但要注意并發訪問問題,可能需要在應用層面實現數據同步機制,如使用鎖機制或事務處理。
? ? ? 對于數據庫、日志文件等關鍵數據,應將其存儲在數據卷中,確保數據的持久化和可恢復性。例如,對于 MySQL 容器,將數據目錄?/var/lib/mysql
?掛載到數據卷上。