Docker 必知必會4----容器之間的通訊

王若伊_恩赐解脱發表於2024-05-23

前面幾篇文章,我們聊了docker的基本概念,以及基本的操作手段:

https://www.cnblogs.com/jilodream/p/18177695 初識docker
https://www.cnblogs.com/jilodream/p/18184687 基本操作
https://www.cnblogs.com/jilodream/p/18189478 映象製作

但是現在隨著分散式多節點的考慮,我們往往需要容器之間可以進行通訊。
容器之間的通訊一般分為(防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )三種途徑:
1、透過虛擬ip直接訪問
2、透過link方式,指定要連線的容器
3、建立bridge網路,來實現容器互聯

為了滿足接下來的學習,我們需要利用官方的tomcat映象為基礎,初始化一些指令,DockerFile 如下:

 1 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# cat Dockerfile 
 2 #指定基礎映象
 3 FROM tomcat:my-tomcat-image  
 4 
 5 #指定維護人員
 6 MAINTAINER wangruoyi "encijietuo@123.com"  
 7 
 8  # 設定環境變數
 9 ENV BASE_DIR="/usr/local/" 
10 
11 #指定工作路徑
12 WORKDIR /$BASE_DIR  
13 
14 #刪除原有的webapps 資料夾
15 RUN rm -rf ./tomcat/webapps && cp -r  ./tomcat/webapps.dist  ./tomcat/webapps  && apt-get update && apt-get install net-tools && apt install iputils-ping -y
16 
17 #暴露8080埠,其實沒有必要,因為原有的
18 EXPOSE   8080
19 
20 #ENTRYPOINT ["echo 'hello myImage'"]

開始構建映象,並檢視

1 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker  build  -t new  .
2 省略部分輸出
3 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker images 
4 REPOSITORY                     TAG               IMAGE ID       CREATED        SIZE
5 new                            latest            9a36ac14523d   21 hours ago   706MB

然後我們回到重點,依次來看看容器的3種通訊途徑:

1、透過虛擬ip直接訪問
安裝docker之後,docker會預設搭建一個docker0的網路,後續每個容器就是網路中的一個節點,(防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )每個節點因此會有屬於網路中的一個虛擬ip。我們可以利用虛擬ip直接進行訪問。
如下,我們建立兩個容器:

1 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker run -p 8081:8080 -d --name mytom8081 9a36ac14523d
2 f3f1b0f09320e6e42e704625fa4aa2d544a553976cf38dba7c1dcddfe65e8563
3 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker run -p 8082:8080 -d --name mytom8082 9a36ac14523d
4 744a1395c38840cc01659ec9fa2d55026389ca5d99387092de1d23c026613a65
5 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker ps 
6 CONTAINER ID   IMAGE          COMMAND             CREATED         STATUS         PORTS                    NAMES
7 744a1395c388   9a36ac14523d   "catalina.sh run"   3 minutes ago   Up 3 minutes   0.0.0.0:8082->8080/tcp   mytom8082
8 f3f1b0f09320   9a36ac14523d   "catalina.sh run"   3 minutes ago   Up 3 minutes   0.0.0.0:8081->8080/tcp   mytom8081

我們可以透過ifconfig或者inspect 檢視容器ip,接著使用 ping 和curl 命令實現兩個容器的互相訪問,我們發現網路是通著的:

進入8081容器,並檢視ip為172.17.0.2

1 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker exec -it f3f1b0f09320  /bin/bash
2 root@f3f1b0f09320:/usr/local# ifconfig
3 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
4         inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
5 
6 以下省略部分

進入8082容器,,並檢視ip為172.17.0.3

1 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker exec -it 744a1395c388 /bin/bash
2 root@744a1395c388:/usr/local# ifconfig
3 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
4         inet 172.17.0.3  netmask 255.255.0.0  broadcast 172.17.255.255
5         inet6 fe80::42:acff:fe11:3  prefixlen 64  scopeid 0x20<link>
6 
7 以下省略部分

8081 ping 8082,並訪問對方tomcat埠

 1 root@f3f1b0f09320:/usr/local# ping 172.17.0.3
 2 PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
 3 64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.218 ms
 4 64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.084 ms
 5 ^C
 6 --- 172.17.0.3 ping statistics ---
 7 2 packets transmitted, 2 received, 0% packet loss, time 1000ms
 8 rtt min/avg/max/mdev = 0.084/0.151/0.218/0.067 ms
 9 root@f3f1b0f09320:/usr/local# curl 172.17.0.3:8080
10 
11 
12 
13 <!DOCTYPE html>
14 <html lang="en">
15     <head>
16         <meta charset="UTF-8" />
17         <title>Apache Tomcat/10.0.14</title>
18 
19 以下省略部分

8082 ping 8081,並訪問對方tomcat埠

 1 root@744a1395c388:/usr/local# ping 172.17.0.2
 2 PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
 3 64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.150 ms
 4 ^C
 5 --- 172.17.0.2 ping statistics ---
 6 1 packets transmitted, 1 received, 0% packet loss, time 0ms
 7 rtt min/avg/max/mdev = 0.150/0.150/0.150/0.000 ms
 8 root@744a1395c388:/usr/local# curl 172.17.0.2:8080
 9 
10 
11 
12 <!DOCTYPE html>
13 <html lang="en">
14     <head>
15         <meta charset="UTF-8" />

這種情況一般比較簡單,而且實際搭建網路叢集時,比較複雜,ip地址也不好維護,所以我們一般只是在環境測試時使用。

2、透過link方式,指定要連線的容器
命令描述如下:

docker run -d --name 容器名稱 --link 被連線容器名:被連線容器別名 映象Id

我們建立兩個容器。然後透過ifconfig或者inspect 檢視容器ip

我們可以直接透過(防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )別名來訪問另外一個容器,
以下為8081容器:ip為172.17.0.2:

 1 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker run -p 8081:8080 -d --name mytom8081 9a36ac14523d
 2 ce95c0e7a3f10a3623c0c86ef38caaa33a758ca15fd2a246757686c7329c9092
 3 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker ps
 4 CONTAINER ID   IMAGE          COMMAND             CREATED          STATUS          PORTS                    NAMES
 5 a67f455d6bf0   9a36ac14523d   "catalina.sh run"   15 seconds ago   Up 15 seconds   0.0.0.0:8082->8080/tcp   mytom8082
 6 ce95c0e7a3f1   9a36ac14523d   "catalina.sh run"   18 minutes ago   Up 18 minutes   0.0.0.0:8081->8080/tcp   mytom8081
 7 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker exec -it ce95c0e7a3f1 /bin/bash
 8 root@ce95c0e7a3f1:/usr/local# ifconfig
 9 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
10         inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
11         inet6 fe80::42:acff:fe11:2  prefixlen 64  scopeid 0x20<link>

以下為8082容器,ip為172.17.0.3 :

1 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker run -p 8082:8080 -d --name mytom8082 --link mytom8081:mytom8081alias  9a36ac14523d
2 a67f455d6bf0d37b9fb43769d6d93d0e59903fb585b2fd4d37434b3199394869
3 
4 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker exec -it  a67f455d6bf0 /bin/bash
5 root@a67f455d6bf0:/usr/local# ifconfig
6 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
7         inet 172.17.0.3  netmask 255.255.0.0  broadcast 172.17.255.255

8082容器透過ip和網路別名訪問8081容器:

 1 root@a67f455d6bf0:/usr/local# ping 172.17.0.2
 2 PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
 3 64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.158 ms
 4 64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.063 ms
 5 ^C
 6 --- 172.17.0.2 ping statistics ---
 7 2 packets transmitted, 2 received, 0% packet loss, time 999ms
 8 rtt min/avg/max/mdev = 0.063/0.110/0.158/0.047 ms
 9 root@a67f455d6bf0:/usr/local# ping mytom8081alias
10 PING mytom8081alias (172.17.0.2) 56(84) bytes of data.
11 64 bytes from mytom8081alias (172.17.0.2): icmp_seq=1 ttl=64 time=0.081 ms
12 64 bytes from mytom8081alias (172.17.0.2): icmp_seq=2 ttl=64 time=0.063 ms
13 ^C
14 --- mytom8081alias ping statistics ---
15 2 packets transmitted, 2 received, 0% packet loss, time 1000ms
16 rtt min/avg/max/mdev = 0.063/0.072/0.081/0.009 ms
17 root@a67f455d6bf0:/usr/local# curl mytom8081alias:8080
18 
19 
20 
21 <!DOCTYPE html>
22 <html lang="en">

link方式本質上還是使用docker0網路,(防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )修改host檔案的ip對映,來實現網路通訊。並且隨著ip的變化還可以動態的維護這種對映關係。

但是link方式也有自己的侷限性,如只能單向請求,兩個容器無法互相連線請求對方,因為link配置是在啟動容器時就已經生成好的,也就是隻能後邊的容器單向請求前邊的容器,無法形成迴圈的網路。由於諸多不便,link方式也被拋棄了,更推薦的是bridge網路方式。

3、建立bridge網路,來實現容器互聯

(1)首先我們建立一個bridge網路:
docker network create 網路名稱

如下,我們建立一個網路名稱為mynet的網路

 1 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker network ls
 2 NETWORK ID     NAME      DRIVER    SCOPE
 3 aa377d4ce411   bridge    bridge    local
 4 39d44fbbca56   host      host      local
 5 2b8ed0e20118   none      null      local
 6 
 7 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker network create mynet
 8 fd1097786e75a0e3b7160fdacc49f60d815457dbbcc4654bb138136f02d9cb54
 9 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker network ls
10 NETWORK ID     NAME      DRIVER    SCOPE
11 aa377d4ce411   bridge    bridge    local
12 39d44fbbca56   host      host      local
13 fd1097786e75   mynet     bridge    local
14 2b8ed0e20118   none      null      local

(2)新建立3個容器加入到bridege網路中

命令如下docker run -it --name 容器名 ---network bridge網路名 --network-alias 當前容器在網路中的別名 映象名

 1 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker run -p 8083:8080 -d --name mytom8083 --network mynet --network-alias mytom8083alias  9a36ac14523d
 2 1d993226c559408a54d18f9258d2dc196283dc5b6b0cffa2d113b4eef579f7c4
 3 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker run -p 8084:8080 -d --name mytom8084 --network mynet --network-alias mytom8084alias  9a36ac14523d
 4 c7de74283019bccfc87174941afdeb2fbbd0137496094bd7fd9d6a500352a4ad
 5 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker run -p 8085:8080 -d --name mytom8085 --network mynet --network-alias mytom8085alias 9a36ac14523d
 6 28c5fa396b54649edc31c52c4cdf85a96063919272a12f61b208cfb99f1325f9
 7 
 8 CONTAINER ID   IMAGE          COMMAND             CREATED          STATUS          PORTS                    NAMES
 9 28c5fa396b54   9a36ac14523d   "catalina.sh run"   4 minutes ago    Up 45 seconds   0.0.0.0:8085->8080/tcp   mytom8085
10 c7de74283019   9a36ac14523d   "catalina.sh run"   13 minutes ago   Up 13 minutes   0.0.0.0:8084->8080/tcp   mytom8084
11 1d993226c559   9a36ac14523d   "catalina.sh run"   14 minutes ago   Up 13 minutes   0.0.0.0:8083->8080/tcp   mytom8083

(3)進入到3個容器中,分別訪問其它容器

以下為8083容器:8083訪問8084

1 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker exec -it 1d993226c559   /bin/bash
2 root@1d993226c559:/usr/local# curl  mytom8084alias:8080
3 
4 
5 
6 <!DOCTYPE html>
7 <html lang="en">
8     <head>
9         <meta charset="UTF-8" />

以下為8084容器: 8084訪問8083

 1 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker exec -it c7de74283019  /bin/bash
 2 root@c7de74283019:/usr/local# 
 3 root@c7de74283019:/usr/local# 
 4 root@c7de74283019:/usr/local# 
 5 root@c7de74283019:/usr/local# ping mytom8083alias
 6 PING mytom8083alias (172.18.0.2) 56(84) bytes of data.
 7 64 bytes from mytom8083.mynet (172.18.0.2): icmp_seq=1 ttl=64 time=0.151 ms
 8 64 bytes from mytom8083.mynet (172.18.0.2): icmp_seq=2 ttl=64 time=0.057 ms
 9 ^C
10 --- mytom8083alias ping statistics ---
11 2 packets transmitted, 2 received, 0% packet loss, time 1001ms
12 rtt min/avg/max/mdev = 0.057/0.104/0.151/0.047 ms
13 root@c7de74283019:/usr/local# curl  mytom8083alias:8080
14 
15 
16 
17 <!DOCTYPE html>
18 <html lang="en">
19     <head>
20         <meta charset="UTF-8" />
21         <title>Apache Tomcat/10.0.14</title>

以下為8085容器:8085訪問8083、8084

 1 [root@iZ2ze3bpa0o5cw6gp42ry2Z ~]# docker exec -it 28c5fa396b54 /bin/bash
 2 root@28c5fa396b54:/usr/local# curl mytom8083alias:8080
 3 
 4 <!DOCTYPE html>
 5 <html lang="en">
 6     <head>
 7         <meta charset="UTF-8" />
 8         <title>Apache Tomcat/10.0.14</title>
 9         <link href="favicon.ico" rel="icon" type="image/x-icon" />
10         <link href="tomcat.css" rel="stylesheet" type="text/css" />
11 
12 省略若干
13 
14 root@28c5fa396b54:/usr/local# curl mytom8084alias:8080
15 <!DOCTYPE html>
16 <html lang="en">
17     <head>
18         <meta charset="UTF-8" />
19         <title>Apache Tomcat/10.0.14</title>
20         <link href="favicon.ico" rel="icon" type="image/x-icon" />
21         <link href="tomcat.css" rel="stylesheet" type="text/css" />

我們可以發現第三種(構建bridge網路)的方式,相對來說最為靈活實用,不需要提前規劃,並且可以實現網狀的網路通訊請求。

回到訴求本身,其實我們隊容器間的通訊訴求並沒有想象中的那麼迫切,我們往往是透過埠對映到宿主機中,透過訪問不同的宿主機ip和埠來實現容器間通訊。這樣也遮蔽了宿主機中容器的概念,並且可以廣泛的無差別使用各種中介軟體,使得開發起來更容易。

但是有時候出於網路安全考慮,不允許請求進行跳轉,或者埠進行遮蔽,此時就需要考慮下是否可以使用容器通訊的技術來實現訴求。

相關文章