使用覆蓋網路聯網

本系列教程討論了針對 Swarm 服務的網路。有關獨立容器的網路,請參閱 獨立容器的網路。如果您需要了解有關 Docker 網路的更多資訊,請參閱 概述

本頁包含以下教程。您可以在 Linux、Windows 或 Mac 上執行每個教程,但對於最後一個教程,您需要另一個在其他位置執行的 Docker 主機。

  • 使用預設覆蓋網路 演示瞭如何使用 Docker 在您初始化或加入 Swarm 時自動為您設定的預設覆蓋網路。此網路不是生產系統的最佳選擇。

  • 使用使用者定義的覆蓋網路 展示瞭如何建立和使用您自己的自定義覆蓋網路來連線服務。建議在生產環境中執行的服務使用此方法。

  • 將覆蓋網路用於獨立容器 展示瞭如何使用覆蓋網路在不同 Docker 守護程式上的獨立容器之間進行通訊。

先決條件

這些教程要求您至少擁有單個節點 Swarm,這意味著您已啟動 Docker 並在主機上運行了 docker swarm init。您也可以在多節點 Swarm 上執行這些示例。

使用預設覆蓋網路

在此示例中,您啟動 alpine 服務並從各個服務容器的角度檢查網路的特性。

本教程不會深入介紹有關覆蓋網路實現方式的作業系統特定細節,而是重點介紹覆蓋網路從服務角度的功能。

先決條件

本教程需要三個物理或虛擬 Docker 主機,這些主機可以彼此通訊。本教程假設這三個主機在同一個網路上執行,並且沒有涉及防火牆。

這些主機將分別稱為 managerworker-1worker-2manager 主機將同時充當管理器和工作節點,這意味著它可以同時執行服務任務和管理 Swarm。worker-1worker-2 將僅充當工作節點。

如果您沒有三個主機,一個簡單的解決方案是在像 Amazon EC2 這樣的雲提供商上設定三個 Ubuntu 主機,這些主機都在同一個網路上,並且所有主機之間都允許通訊(使用 EC2 安全組等機制),然後按照 Ubuntu 上 Docker Engine - Community 的安裝說明 進行操作。

演練

建立 Swarm

完成此過程後,所有三個 Docker 主機都將加入 Swarm,並將使用名為 ingress 的覆蓋網路連線在一起。

  1. manager 上,初始化 Swarm。如果主機只有一個網路介面,則 --advertise-addr 標誌是可選的。

    $ docker swarm init --advertise-addr=<IP-ADDRESS-OF-MANAGER>
    

    記下列印的文字,因為其中包含用於將 worker-1worker-2 加入 Swarm 的令牌。建議將令牌儲存在密碼管理器中。

  2. worker-1 上,加入 Swarm。如果主機只有一個網路介面,則 --advertise-addr 標誌是可選的。

    $ docker swarm join --token <TOKEN> \
      --advertise-addr <IP-ADDRESS-OF-WORKER-1> \
      <IP-ADDRESS-OF-MANAGER>:2377
    
  3. worker-2 上,加入 Swarm。如果主機只有一個網路介面,則 --advertise-addr 標誌是可選的。

    $ docker swarm join --token <TOKEN> \
      --advertise-addr <IP-ADDRESS-OF-WORKER-2> \
      <IP-ADDRESS-OF-MANAGER>:2377
    
  4. manager 上,列出所有節點。此命令只能從管理器執行。

    $ docker node ls
    
    ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
    d68ace5iraw6whp7llvgjpu48 *   ip-172-31-34-146    Ready               Active              Leader
    nvp5rwavvb8lhdggo8fcf7plg     ip-172-31-35-151    Ready               Active
    ouvx2l7qfcxisoyms8mtkgahw     ip-172-31-36-89     Ready               Active
    

    您還可以使用 --filter 標誌按角色進行過濾

    $ docker node ls --filter role=manager
    
    ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
    d68ace5iraw6whp7llvgjpu48 *   ip-172-31-34-146    Ready               Active              Leader
    
    $ docker node ls --filter role=worker
    
    ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
    nvp5rwavvb8lhdggo8fcf7plg     ip-172-31-35-151    Ready               Active
    ouvx2l7qfcxisoyms8mtkgahw     ip-172-31-36-89     Ready               Active
    
  5. 列出 managerworker-1worker-2 上的 Docker 網路,並注意它們現在都具有一個名為 ingress 的覆蓋網路和一個名為 docker_gwbridge 的橋接網路。這裡只顯示了 manager 的列表

    $ docker network ls
    
    NETWORK ID          NAME                DRIVER              SCOPE
    495c570066be        bridge              bridge              local
    961c6cae9945        docker_gwbridge     bridge              local
    ff35ceda3643        host                host                local
    trtnl4tqnc3n        ingress             overlay             swarm
    c8357deec9cb        none                null                local
    

docker_gwbridgeingress 網路連線到 Docker 主機的網路介面,以便流量可以流向和流出 Swarm 管理器和工作節點。如果您建立 Swarm 服務並且沒有指定網路,它們將連線到 ingress 網路。建議您為每個應用程式或將協同工作的應用程式組使用單獨的覆蓋網路。在下一個過程中,您將建立兩個覆蓋網路並將服務連線到每個網路。

建立服務

  1. manager 上,建立一個名為 nginx-net 的新覆蓋網路

    $ docker network create -d overlay nginx-net
    

    您無需在其他節點上建立覆蓋網路,因為當其中一個節點開始執行需要它的服務任務時,它將自動建立。

  2. manager 上,建立一個連線到 nginx-net 的 5 個副本的 Nginx 服務。該服務將埠 80 釋出到外部世界。所有服務任務容器都可以相互通訊,而無需開啟任何埠。

    注意

    服務只能在管理器上建立。

    $ docker service create \
      --name my-nginx \
      --publish target=80,published=80 \
      --replicas=5 \
      --network nginx-net \
      nginx
    

    ingress 的預設釋出模式(在您未為 --publish 標誌指定 mode 時使用)意味著如果您瀏覽到 managerworker-1worker-2 上的埠 80,您將連線到 5 個服務任務之一的埠 80,即使當前沒有任務在您瀏覽到的節點上執行。如果您想使用 host 模式釋出埠,可以在 --publish 輸出中新增 mode=host。但是,在這種情況下,您還應該使用 --mode global 而不是 --replicas=5,因為在給定節點上,只有一個服務任務可以繫結給定埠。

  3. 執行 docker service ls 以監控服務啟動的進度,這可能需要幾秒鐘。

  4. 檢查 managerworker-1worker-2 上的 nginx-net 網路。請記住,您無需在 worker-1worker-2 上手動建立它,因為 Docker 會為您建立它。輸出將很長,但請注意 ContainersPeers 部分。Containers 列出了從該主機連線到覆蓋網路的所有服務任務(或獨立容器)。

  5. manager,使用 docker service inspect my-nginx 檢查服務,並注意有關服務使用的埠和端點的資訊。

  6. 建立一個名為 nginx-net-2 的新網路,然後更新服務以使用此網路而不是 nginx-net

    $ docker network create -d overlay nginx-net-2
    
    $ docker service update \
      --network-add nginx-net-2 \
      --network-rm nginx-net \
      my-nginx
    
  7. 執行 docker service ls 以驗證服務是否已更新,並且所有任務是否已重新部署。執行 docker network inspect nginx-net 以驗證沒有任何容器連線到它。對 nginx-net-2 執行相同的命令,並注意所有服務任務容器都連線到它。

    注意

    即使覆蓋網路在需要時會在 Swarm 工作節點上自動建立,但它們不會自動刪除。

  8. 清理服務和網路。從 manager 執行以下命令。管理器將指示工作節點自動刪除網路。

    $ docker service rm my-nginx
    $ docker network rm nginx-net nginx-net-2
    

使用使用者定義的覆蓋網路

先決條件

本教程假設 Swarm 已設定,並且您位於管理器上。

演練

  1. 建立使用者定義的覆蓋網路。

    $ docker network create -d overlay my-overlay
    
  2. 使用覆蓋網路啟動服務,並將埠 80 釋出到 Docker 主機上的埠 8080。

    $ docker service create \
      --name my-nginx \
      --network my-overlay \
      --replicas 1 \
      --publish published=8080,target=80 \
      nginx:latest
    
  3. 執行 docker network inspect my-overlay 並驗證 my-nginx 服務任務是否連線到它,方法是檢視 Containers 部分。

  4. 刪除服務和網路。

    $ docker service rm my-nginx
    
    $ docker network rm my-overlay
    

將覆蓋網路用於獨立容器

此示例演示了 DNS 容器發現,具體來說,是如何使用覆蓋網路在不同 Docker 守護程式上的獨立容器之間進行通訊。步驟如下

  • host1 上,將節點初始化為 Swarm(管理器)。
  • host2 上,將節點加入 Swarm(工作節點)。
  • host1 上,建立一個可附加的覆蓋網路(test-net)。
  • host1 上,執行一個互動式 alpine 容器(alpine1)在 test-net 上。
  • host2上,執行一個互動式且分離的alpine 容器 (alpine2) 在 test-net 上。
  • host1上,從alpine1會話中,ping alpine2

先決條件

對於此測試,您需要兩個可以相互通訊的不同 Docker 主機。每個主機必須在兩個 Docker 主機之間開啟以下埠

  • TCP 埠 2377
  • TCP 和 UDP 埠 7946
  • UDP 埠 4789

設定此操作的一種簡單方法是擁有兩臺虛擬機器(本地或在 AWS 等雲提供商上),每臺都安裝並執行 Docker。如果您使用 AWS 或類似的雲計算平臺,最簡單的配置是使用安全組,該組在兩個主機之間開啟所有傳入埠以及來自您客戶端 IP 地址的 SSH 埠。

此示例將我們 swarm 中的兩個節點稱為host1host2。此示例還使用 Linux 主機,但相同的命令在 Windows 上也能正常工作。

演練

  1. 設定 swarm。

    a. 在host1上,初始化一個 swarm(如果提示,使用--advertise-addr 指定與 swarm 中其他主機通訊的介面的 IP 地址,例如,AWS 上的私有 IP 地址)

    $ docker swarm init
    Swarm initialized: current node (vz1mm9am11qcmo979tlrlox42) is now a manager.
    
    To add a worker to this swarm, run the following command:
    
        docker swarm join --token SWMTKN-1-5g90q48weqrtqryq4kj6ow0e8xm9wmv9o6vgqc5j320ymybd5c-8ex8j0bc40s6hgvy5ui5gl4gy 172.31.47.252:2377
    
    To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
    

    b. 在host2上,按照上述說明加入 swarm

    $ docker swarm join --token <your_token> <your_ip_address>:2377
    This node joined a swarm as a worker.
    

    如果節點無法加入 swarm,則docker swarm join 命令會超時。要解決此問題,請在host2上執行docker swarm leave --force,驗證您的網路和防火牆設定,然後重試。

  2. host1上,建立一個名為test-net 的可附加覆蓋網路

    $ docker network create --driver=overlay --attachable test-net
    uqsof8phj3ak0rq9k86zta6ht
    

    注意返回的 **NETWORK ID** -- 您將在從host2 連線時再次看到它。

  3. host1上,啟動一個互動式 (-it) 容器 (alpine1),該容器連線到test-net

    $ docker run -it --name alpine1 --network test-net alpine
    / #
    
  4. host2上,列出可用的網路 -- 注意test-net 尚未存在

    $ docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    ec299350b504        bridge              bridge              local
    66e77d0d0e9a        docker_gwbridge     bridge              local
    9f6ae26ccb82        host                host                local
    omvdxqrda80z        ingress             overlay             swarm
    b65c952a4b2b        none                null                local
    
  5. host2上,啟動一個分離的 (-d) 和互動式的 (-it) 容器 (alpine2),該容器連線到test-net

    $ docker run -dit --name alpine2 --network test-net alpine
    fb635f5ece59563e7b8b99556f816d24e6949a5f6a5b1fbd92ca244db17a4342
    

    注意

    自動 DNS 容器發現僅適用於具有唯一容器名稱的容器。

  6. host2上,驗證test-net 是否已建立(並且具有與host1 上的test-net 相同的 NETWORK ID)

    $ docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    ...
    uqsof8phj3ak        test-net            overlay             swarm
    
  7. host1上,在alpine1 的互動式終端中 ping alpine2

    / # ping -c 2 alpine2
    PING alpine2 (10.0.0.5): 56 data bytes
    64 bytes from 10.0.0.5: seq=0 ttl=64 time=0.600 ms
    64 bytes from 10.0.0.5: seq=1 ttl=64 time=0.555 ms
    
    --- alpine2 ping statistics ---
    2 packets transmitted, 2 packets received, 0% packet loss
    round-trip min/avg/max = 0.555/0.577/0.600 ms
    

    兩個容器透過連線兩個主機的覆蓋網路進行通訊。如果您在host2 上執行另一個非分離 的 alpine 容器,則可以從host2 ping alpine1(並且在這裡我們添加了刪除選項,以便自動清理容器)

    $ docker run -it --rm --name alpine3 --network test-net alpine
    / # ping -c 2 alpine1
    / # exit
  8. host1 上,關閉alpine1 會話(這也將停止容器)

    / # exit
    
  9. 清理您的容器和網路

    您必須分別停止並刪除每個主機上的容器,因為 Docker 守護程式獨立執行,這些是獨立的容器。您只需要在host1 上刪除網路,因為當您在host2 上停止alpine2 時,test-net 會消失。

    a. 在host2 上,停止alpine2,檢查test-net 是否已刪除,然後刪除alpine2

    $ docker container stop alpine2
    $ docker network ls
    $ docker container rm alpine2
    

    a. 在host1 上,刪除alpine1test-net

    $ docker container rm alpine1
    $ docker network rm test-net
    

其他網路教程