文章目錄
- 1. Docker默認的網路模式
- 1.1 host模式
- 1.2 container模式
- 1.3 none模式
- 1.4 bridge模式
- 2. 容器互聯
- 3. 自定義網路
- 4. Docker網路之間的互聯
- 5. Docker網路實戰練習
- 5.1 Redis集群部署
- 5.2 SpringBoot專案打包鏡像
1. Docker默認的網路模式
使用以下命令查看所有的Docker網路:
docker network ls

Docker默認提供了四個網路模式,說明:
-
bridge:容器默認的網路是橋接模式(自己搭建的網路默認也是使用橋接模式,啟動容器默認也是使用橋接模式),此模式會為每一個容器分配、設定IP等,并將容器連接到一個docker0虛擬網橋,通過docker0網橋以及Iptables nat表配置與宿主機通信,
-
none:不配置網路,容器有獨立的Network namespace,但并沒有對其進行任何網路設定,如分配veth pair 和網橋連接,配置IP等,
-
host:容器和宿主機共享Network namespace,容器將不會虛擬出自己的網卡,配置自己的IP等,而是使用宿主機的IP和埠,
-
container:創建的容器不會創建自己的網卡,配置自己的IP容器網路連通,容器和另外一個容器共享Network namespace(共享IP、埠范圍),
容器默認使用bridge網路模式,我們使用該docker run --network=選項指定容器使用的網路:
- host模式:使用 --net=host 指定,
- none模式:使用 --net=none 指定,
- bridge模式:使用 --net=bridge 指定,默認設定,
- container模式:使用 --net=container:NAME_or_ID 指定,
1.1 host模式
Namespace的簡要說明:
Docker使用了Linux的Namespaces技術來進行資源隔離,如PID Namespace隔離行程,Mount Namespace隔離檔案系統,Network Namespace隔離網路等,一個Network Namespace提供了一份獨立的網路環境,包括網卡、路由、Iptable規則等都與其他的NetworkNamespace隔離,一個Docker容器一般會分配一個獨立的Network Namespace,
如果啟動容器的時候使用host模式,那么這個容器將不會獲得一個獨立的Network Namespace,而是和宿主機共用一個Network Namespace,容器將不會虛擬出自己的網卡,配置自己的IP等,而是使用宿主機的IP和埠,但是,容器的其他方面,如檔案系統、行程串列等還是和宿主機隔離的,
使用host模式的容器可以直接使用宿主機的IP地址與外界通信,容器內部的服務埠也可以使用宿主機的埠,不需要進行NAT,host最大的優勢就是網路性能比較好,但是docker host上已經使用的埠就不能再用了,網路的隔離性不好,Host模式的模型圖,如下圖所示:

備注:eth0為宿主機的10.126.130.4為宿主機的內網地址,
1.2 container模式
這個模式指定新創建的容器和已經存在的一個容器共享一個 Network Namespace,而不是和宿主機共享,新創建的容器不會創建自己的網卡,配置自己的 IP,而是和一個指定的容器共享 IP、埠范圍等,同樣,兩個容器除了網路方面,其他的如檔案系統、行程串列等還是隔離的,兩個容器的行程可以通過 lo 網卡設備通信,Container模式模型示意圖如下:

1.3 none模式
使用none模式,Docker容器擁有自己的Network Namespace,但是,并不為Docker容器進行任何網路配置,也就是說,這個Docker容器沒有網卡、IP、路由等資訊,需要我們自己為Docker容器添加網卡、配置IP等,
這種網路模式下容器只有lo回環網路,沒有其他網卡,none模式可以在容器創建時通過–network=none來指定,這種型別的網路沒有辦法聯網,封閉的網路能很好的保證容器的安全性,
None模式示意圖:

1.4 bridge模式
當Docker行程啟動時,會在主機上創建一個名為docker0的虛擬網橋,此主機上啟動的Docker容器會連接到這個虛擬網橋上,虛擬網橋的作業方式和物理交換機類似,這樣主機上的所有容器就通過交換機連在了一個二層網路中,
從docker0子網中分配一個IP給容器使用,并設定docker0的IP地址為容器的默認網關,在主機上創建一對虛擬網卡veth pair設備,Docker將veth pair設備的一端放在新創建的容器中,并命名為eth0(容器的網卡),另一端放在主機中,以vethxxx這樣類似的名字命名,并將這個網路設備加入到docker0網橋中,可以通過brctl show命令查看,
bridge模式是docker的默認網路模式,不寫–net引數,就是bridge模式,使用docker run -p時,docker實際是在iptables做了DNAT規則,實作埠轉發功能,可以使用iptables -t nat -vnL查看,bridge模式如下圖所示:

當Docker server啟動時,會在主機上創建一個名為docker0的虛擬網橋,此主機上啟動的Docker容器會連接到這個虛擬網橋上,Docker0使用到的技術是evth-pair技術,在默認bridge網路模式下,我們每啟動一個Docker容器,Docker就會給Docker容器配置一個ip,
Docker容器完成bridge網路配置的程序如下:
- 在主機上創建一對虛擬網卡veth pair設備,veth設備總是成對出現的,它們組成了一個資料的通道,資料從一個設備進入,就會從另一個設備出來,因此,veth設備常用來連接兩個網路設備,
- Docker將veth pair設備的一端放在新創建的容器中,并命名為eth0,另一端放在主機中,以veth65f9這樣類似的名字命名,并將這個網路設備加入到docker0網橋中,
- 從docker0子網中分配一個IP給容器使用,并設定docker0的IP地址為容器的默認網關,
執行命令 ip addr,可以看到安裝Docker后,默認宿主機有三個地址,

Docker是如何處理容器網路訪問的呢?啟動一個容器,進入容器使用ip addr查看網路設定
docker run -d -P --name tomcat01 tomcat:8.0

可以看到容器啟動后Docker分配給容器一個格式如eth0@if262 的ip地址,宿主機運行ip addr命令查看變化:
可以看到容器內部和Linux主機都會創建一個新的網卡,而這兩個網卡都是成對的,使用的技術就是evth-pair,evth-pair 就是一對的虛擬設備介面,他們是成對出現的,一段連著協議,一段彼此相連,evth-pair充當一個橋梁,連接各種虛擬網路設備,
==Linux主機可以直接網路連接Docker容器,Docker容器和容器之間同樣可以直接網路連接的,==下面具體實驗驗證一下,
docker exec -it tomcat01 ip addr

下面再啟動一個Tomcat容器,嘗試容器之間的網路連接是否能夠成功,


嘗試在tomcat01容器中ping tomcat02容器,可以看到兩個容器是可以連接上的,兩個Tomcat容器之間的網路互動模型圖如下:

說明:
Tomcat01和Tomcat02都使用公用的路由器docker0,所有的容器不指定網路下,都是由docker0路由的,Docker會給我們容器默認分配一個隨機的可用IP地址,
容器網路互聯的通用模型,如下圖所示:

Docker中的所有的網路介面都是虛擬的,只要容器洗掉,容器對應的網橋也會洗掉,
2. 容器互聯
在微服務部署的場景下,注冊中心是使用服務名來唯一識別微服務的,而我們上線部署的時候微服務對應的IP地址可能會改動,所以我們需要使用容器名來配置容器間的網路連接,使用–link可以完成這個功能,
首先不設定連接的情況下,是無法通過容器名來進行連接的,

下面啟動一個Tomcat容器Tomcat03使用–link 連接已經啟動的Tomcat02容器,這樣容器Tomcat03就可以通過容器名Tomcat02連接到容器Tomcat02,

但是反過來容器Tomcat02通過容器名Tomcat03直接ping容器Tomcat03是不行的,

這是因為--link的原理是在指定運行的容器上的/etc/hosts檔案中添加容器名和ip地址的映射,如下:

而tomcat02容器不能夠通過容器名連接tomcat03是因為tomcat02容器中并沒有添加容器名tomcat03和ip地址的映射.

目前–link設定容器互連的方式已經不推薦使用,因為docker0不支持容器名訪問,所以更多地選擇自定義網路,
3. 自定義網路
因為docker0,默認情況下不能通過容器名進行訪問,需要通過–link進行設定連接,這樣的操作比較麻煩,更推薦的方式是自定義網路,容器都使用該自定義網路,就可以實作通過容器名來互相訪問了,
下面查看network的相關命令
docker network --help

查看默認的網路bridge的詳細資訊

查看 network create命令的相關引數

下面自定義一個網路
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

引數說明:
--driver bridge #指定bridge驅動程式來管理網路
--subnet 192.168.0.0/16 #指定網段的CIDR格式的子網
--gateway 192.168.0.1 #指定主子網的IPv4或IPv6網關
網路mynet創建成功后,查看網路資訊:
docker network inspect mynet

下面啟動兩個容器,指定使用該自定義網路mynet,測驗處于自定義網路下的容器,是否可以直接通過容器名進行網路訪問,
docker run -d -P --name tomcat-net-01 --net mynet tomcat
docker run -d -P --name tomcat-net-02 --net mynet tomcat
docker network inspect mynet

下面通過容器名來測驗容器tomcat-net-01 和容器tomcat-net-02之間是否能正常網路通信,

可以發現,在我們的自定義網路下,容器之間既可以通過容器名也可以通過ip地址進行網路通信, 我們自定義的網路默認已經幫我們維護了容器間的網路通信問題,這是實作網路互聯的推薦方式,
4. Docker網路之間的互聯
沒有設定的情況下,不同網路間的容器是無法進行網路連接的,如圖,兩個不同的網路docker0和自定義網路mynet的網路模型圖:

在默認網路bridge下啟動容器tomcat-01,嘗試連接mynet網路下的tomcat-net-01容器,

可以看到是無法網路連接的,不同Docker網路之間的容器需要連接的話需要把作為呼叫方的容器注冊一個ip到被呼叫方所在的網路上,需要使用docker connect命令,
下面設定容器tomcat-01連接到mynet網路上,并查看mynet的網路詳情,可以看到給容器tomcat-01分配了一個ip地址,
docker network connect mynet tomcat-01

設定完成后我們就可以實作不同網路之間的容器互聯了,

5. Docker網路實戰練習
5.1 Redis集群部署
下面部署如圖所示的三主三從的Redis集群

首先停掉所有的容器
docker rm -f $(docker ps -aq)

創建網路名為redis的自定義網路
docker network create redis --subnet 172.38.0.0/16

通過以下腳本創建六個Redis 的配置資訊:
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done

下面啟動6個Redis容器,設定對應的容器資料卷掛載,
#第1個Redis容器
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
#第2個Redis容器
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
-v /mydata/redis/node-2/data:/data \
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
#第3個Redis容器
docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
-v /mydata/redis/node-3/data:/data \
-v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
#第4個Redis容器
docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
-v /mydata/redis/node-4/data:/data \
-v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
#第5個Redis容器
docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
-v /mydata/redis/node-5/data:/data \
-v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
#第6個Redis容器
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
-v /mydata/redis/node-6/data:/data \
-v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
或者通過腳本一次性啟動6個Redis容器:
for port in $(seq 1 6); \
do
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf; \
done
執行上述腳本,運行結果如下:

下面進入到redis-1容器中創建集群
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
查看集群資訊
redis-cli -c
cluster info

查看節點資訊cluster nodes,可以清楚的看到Redis節點的主從關系,

測驗主從復制是否生效,設定一個key,可以看到我們重定向到了Redis-3節點,處理該操作的是Redis-3節點,

新建一個會話,停止Redis-3容器服務,此時重新連接Redis-cli客戶端,再次獲取k1,重定向到了Redis-3節點的從節點Redis-4中處理,

5.2 SpringBoot專案打包鏡像
SpringBoot專案打包鏡像分為以下五個步驟
(1)構建SpringBoot專案
在idea中構建一個最簡單的Spring Boot專案,寫一個介面,啟動專案本地測驗能否正常呼叫,
/**
* @author ethan
* @since 2020-04-22 20:26:31
*/
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "Hello World!";
}
}
(2)打包應用
使用Maven的package打包Spring Boot專案,生成jar包

(3)撰寫Dockerfile
撰寫Dockerfile,內容如下
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
(4)構建鏡像
將打包生成的jar包和撰寫的Dockerfile檔案發送到服務器上

使用build命令構建鏡像
docker build -t demo .

(5)發布運行
完成鏡像的構建后,運行鏡像,測驗/hello介面能否正常訪問,
docker run -d -p 8080:8080 demo
curl localhost:8080/hello

參考:
1.https://www.bilibili.com/video/BV1og4y1q7M4
2.Docker網路詳解——原理篇
3.Docker四種網路模式
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/375097.html
標籤:其他
