docker 學習記錄 - 容器通信

概要

今日學習並記錄的是 docker 容器之間的通信。

大體思路:

    1. 理解單主機網絡;

    2. 容器如何創建自定義網絡;

    3. 容器間通過自定義網絡進行通信;

docker 容器原有網絡

在這之前,先學習下 docker 默認創建的三個網絡:none、host、bridge

# 網絡查看
docker network ls
NETWORK ID     NAME        DRIVER     SCOPE
594430d2d4bb   bridge      bridge     local
d855b34c5d51   host        host       local
b1ecee29ed5e   none        null       local

接下來,我會依次介紹這三個網絡:

none 網絡如名所示,只有 localhost 網卡,是封閉網絡,不能聯網。什麼時候會用得上呢?如果你的容器不想要聯網,可以選用這個。這裏介紹下在打開容器如何指定使用網絡。

# 在啓動容器時加上 --network=none 即可指定使用none網絡,其他網絡也是這樣
docker run -it --network=none --name=container0 image0 /bin/bash

bridge 網絡是容器啓動後,如果沒有指定會默認 bridge,掛載到 docker0 上面。容器創建後 docker0 會出現一個虛擬網卡,當你進入容器後發現:容器的網卡信息與 docker0 掛載的信息不一樣。

舉例:docker0 的 interfaces 是 v1,容器中 interfaces 是 v2,ip 爲 127.0.0.1

這是因爲 v1 和 v2 是一對 veth pair。veth pair 是成對出現的,連接兩個虛擬以太網端口。網卡一端(v2)在容器,另一端(v1)掛載在 docker0 上,起到連接作用。如果容器的 ip 爲 127.0.0.1,那麼 docker0 也會是同一網段,網關信息也可通過 docker0 查詢。容器創建後,docker 會自動從 brige 中分配一個 IP,這裏 16 位的掩碼保證有足夠多的 IP 可以供容器使用。

# namespace 的概念
namespace是 Linux 內核用來隔離內核資源的方式。通過 namespace 可以讓一些進程只能看到與自己相關的一部分資源,而另外一些進程也只能看到與它們自己相關的資源,這兩撥進程根本就感覺不到對方的存在。具體的實現方式是把一個或多個進程的相關資源指定在同一個 namespace 中。
Linux namespaces 是對全局系統資源的一種封裝隔離,使得處於不同 namespace 的進程擁有獨立的全局系統資源,改變一個 namespace 中的系統資源只會影響當前 namespace 裏的進程,對其他 namespace 中的進程沒有影響。

docker 使用了 Linux 的 Namespaces 技術來進行資源隔離,如 PID Namespace 隔離進程,Mount Namespace 隔離文件系統,Network Namespace 隔離網絡等。一個 Network Namespace 提供了一份獨立的網絡環境,包括網卡、路由、Iptable 規則等都與其他的 Network Namespace 隔離。

host 模式類似於 Vmware 的橋接模式,與宿主機在同一個網絡中,但沒有獨立 IP 地址。一個 Docker 容器一般會分配一個獨立的 Network Namespace。但如果啓動容器的時候使用 host 模式,那麼這個容器將不會獲得一個獨立的 Network Namespace,而是和宿主機共用一個 Network Namespace。容器將不會虛擬出自己的網卡,配置自己的 IP 等,而是使用宿主機的 IP 和端口。如下圖所示,共用網絡協議棧和所有網絡接口:

來自:(46 條消息) Docker 網絡: host 模式_thlzjfefe 的博客 - CSDN 博客_docker host 模式

host 模式特殊:

    1. 性能:省去中間網絡插件,網絡性能會更好;

    2. 靈活性:有些 docker host 使用的端口,其他容器就不能使用,會引起端口衝突;

docker 容器創建自定義網絡

除了默認的三種網絡,其實用戶可以自主創建網絡。docker 提供三種驅動:bridge 、 overlay 、 macvlan。

因爲目的是容器之間通信,所以這裏只記錄 bridge。overlay 、 macvlan 用於創建跨主機網絡。

創建容器網絡:

# 格式 --driver bridge
docker network create --driver bridge net0

創建後生成一個網橋 id

# 查看網橋信息
brctl show
# 查看 net0 信息
docker network inspect net0

但是 net0 的網關和 ip 是 docker 默認分配的,如果需要指定:

# 格式:--subnet 和 --gateway
docker network create --driver bridge --subnet 172.20.0.0/24 --gateway 172.20.0.1 net1
# 可以查看 net1 信息驗證
docker network inspect net1

那麼如果使用 net1 網絡,只需:

docker run -it --network=net1 --name=container_name image_name /bin/bash
# 如果想要指定容器分配的 IP 格式:--ip “ip_id”
docker run -it --network=net1 --ip 172.20.0.30 --name=container_name image_name /bin/bash
# 補充:--subnet 創建靜態 IP

如果兩個容器同時使用的是 net1 網絡,那麼應該是可以互相 ping 通,docker 規定是同一網段可以互相訪問。大家可以自己試驗下。

還有個問題:自己設置的網絡和默認的 bridge 使用的不同的網橋,ping bridge 默認創建的容器(這裏用 httpd 代之)肯定不通。

# 打開 host 的防火牆,查看 iptables ,這裏是網上的,容器名字不準
# iptables-save
......
-A DOCKER-ISOLATION -i br-5d863e9f78b6 -o docker0 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-5d863e9f78b6 -j DROP
......

發現 iptables 丟掉了網橋 docker0 與 br-5d863e9f78b6(net1 的網橋)之間雙向的流量。因爲本來 docker 是隔離不同 network,所以如果通信,需要:

# 爲 httpd 容器添加 net1 的網卡
# 格式:通過docker network connect 命令實現
docker network connect net1 "CONTAINER ID"
# CONTAINER ID 這裏是 httpd 容器的,通過 docker ps 查看
# 可以到 httpd 容器查看網絡信息,會發現增加了一個網卡,分配了 net1 的 IP,這樣可以互相 ping 通

總結:

  1. 兩個容器(使用創建的同一網絡),可以互相通信;

  2. 如果不是使用的同一網絡,可以添加網卡,連接網絡,分配 IP,建立通信。

docker 容器間通信:

docker 通信方式有三種,在自定義網絡中,已經講解了 IP 通信的方式,也是我們經常使用的。總共三種如下:IP , Docker DNS Server , Joined

這裏不在重複描述

docker daemon 通過 DNS server 使容器可以直接通過容器名字進行通信。

# 格式:--name 爲容器命名
# 建立兩個容器,使用自定義網絡 net1
docker run -it --network=net1 --name=container0 image0 /bin/bash
docker run -it --network=net1 --name=container1 image0 /bin/bash
# 通過名字可以互相通信
ping -C 3 container1
# 注意:1.需同在自定義網絡才能使用docker DNS

類似多個容器共享同一網絡棧、網卡、配置信息,可以通過 127.0.0.1 進行互相通信

# 新生成一個容器 container0
docker run -it --name=container0 image0 /bin/bash
# 新生成一個容器 container1 並指定 Joined 容器爲 container0
# 格式: --network=container:container0
docker run -it --network=container:container0 --name=container1 image0 /bin/bash
# 查看 IP 信息 格式:ip a
# 發現 container0 和 container1 的 mac 地址與 IP 一樣,共享了相同的網絡棧。container1 可以直接用 127.0.0.1 訪問 container0
# 使用場景:來自:https://mp.weixin.qq.com/s/pkkir--MRC1Vz9z8CcNc6Q 優秀的公衆號:小白運維之路
# 1.不同容器中的程序希望通過 loopback 高效快速地通信,比如 web server 與 app server。
# 2.希望監控其他容器的網絡流量,比如運行在獨立容器中的網絡監控程序。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/OEWgRZgoVwrLHGNj69mf7A