Docker中的網絡配置

Docker容器和服務如此強大的緣由之一是您能夠將它們鏈接在一塊兒,或將它們鏈接到非Docker工做負載。 Docker容器和服務甚至不須要知道它們已部署在Docker上,也沒必要知道它們的對等對象是否也是Docker工做負載。 不管您的Docker主機運行Linux,Windows仍是二者結合,您均可以使用Docker以與平臺無關的方式管理它們。node

本主題定義了一些基本的Docker網絡概念,並幫助您設計和部署應用程序以充分利用這些功能。nginx

網絡驅動

Docker的網絡子系統使用驅動程序是可插拔的。默認狀況下存在幾個驅動程序,並提供核心網絡功能:docker

  • bridge:默認的網絡驅動程序。 若是您未指定驅動程序,則這是您正在建立的網絡類型。當您的應用程序在須要通訊的獨立容器中運行時,一般會使用網橋網絡。
  • host:對於獨立容器,去掉容器和Docker主機之間的網絡隔離,直接使用主機的網絡。host僅可用於Docker 17.06及更高版本上的集羣服務。
  • overlay:overlay網絡將多個Docker守護程序鏈接在一塊兒,並使羣集服務可以相互通訊。您還可使用overlay網絡來促進羣集服務和獨立容器之間或不一樣Docker守護程序上的兩個獨立容器之間的通訊。這種策略消除了在這些容器之間進行操做系統級路由的須要
  • macvlan:Macvlan網絡容許您將MAC地址分配給容器,使其在網絡上顯示爲物理設備。 Docker守護程序經過其MAC地址將流量路由到容器。 在處理但願直接鏈接到物理網絡而不是經過Docker主機的網絡堆棧進行路由的傳統應用程序時,使用macvlan驅動程序有時是最佳選擇。
  • none:對於此容器,禁用全部聯網。 一般與自定義網絡驅動程序一塊兒使用。none不適用於swarm services.
  • 網絡插件:您能夠在Docker中安裝和使用第三方網絡插件。 這些插件可從Docker Hub或第三方供應商處得到。 有關安裝和使用給定網絡插件的信息,請參閱供應商的文檔。

網絡驅動總結

  • 當須要多個容器在同一Docker主機上通訊時,用戶定義的橋接網絡是最佳選擇。
  • 當網絡堆棧不該該與Docker主機隔離,而但願隔離容器的其餘方面時,主機網絡是最佳選擇。
  • 當您須要在不一樣Docker主機上運行的容器進行通訊時,或者當多個應用程序使用羣服務一塊兒工做時,覆蓋網絡是最好的。
  • 從VM設置遷移或須要容器看起來像網絡上的物理主機時,Macvlan網絡是最好的,每一個主機都有惟一的MAC地址。
  • 第三方網絡插件使您能夠將Docker與專用網絡堆棧集成。

獨立Docker容器的連網

這一部分包含三個不一樣的指南,你能夠在不一樣系統上運行他們,可是對於最後兩個,你須要額外的Docker主機運行。shell

  • 使用默認的橋接網絡:這一章節演示如何使用Docker自動爲您設置的默認橋接網絡。 該網絡不是生產系統的最佳選擇。
  • 使用用戶定義的橋網絡:顯示瞭如何建立和使用本身的自定義橋網絡,以鏈接在同一Docker主機上運行的容器。 建議將其用於生產中運行的獨立容器。

儘管overlay網絡一般用於集羣服務,但Docker 17.06及更高版本容許您將overlay網絡用於獨立容器。 這是使用overlay網絡的教程的一部分。安全

使用默認的橋接網絡

在此示例中,您在同一Docker主機上啓動了兩個不一樣的alpine容器,並進行了一些測試以瞭解它們如何相互通訊。 您須要安裝並運行Docker。bash

1.打開一個終端窗口。 在執行其餘任何操做以前,請先列出當前網絡。 若是您從未在此Docker守護程序上添加網絡或初始化羣組,則應該看到如下內容。 您可能會看到不一樣的網絡,但至少應該看到如下內容(網絡ID會有所不一樣):網絡

$ docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
17e324f45964        bridge              bridge              local
6ed54d316334        host                host                local
7092879f2cc8        none                null                local
複製代碼

列出了默認的橋接網絡,以及hostnone。 後兩個不是徹底成熟的網絡,但用於啓動直接鏈接到Docker守護程序主機的網絡堆棧的容器,或用於啓動不包含網絡設備的容器。 本教程將把兩個容器鏈接到橋接網絡。oop

2.開啓兩個alpine容器運行ash,它是Alpine默認的shell,而不是bash. -dit標誌的意思是啓動分離的容器(在後臺),交互的(具備鍵入的能力)和TTY(以便您能夠看到輸入和輸出)。因爲您是分開啓動的,所以您不會當即鏈接到該容器。而是將打印容器的ID。 由於你未指定任何--network選項,因此容器將鏈接到默認的網橋網絡。測試

$ docker run -dit --name alpine1 alpine ash

$ docker run -dit --name alpine2 alpine ash
複製代碼

檢查兩個容器是否確實已啓動:ui

$ docker container ls

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
602dbf1edc81        alpine              "ash"               4 seconds ago       Up 3 seconds                            alpine2
da33b7aa74b0        alpine              "ash"               17 seconds ago      Up 16 seconds                           alpine1
複製代碼

3.檢查網橋網絡以查看鏈接了哪些容器。

$ docker network inspect bridge

[
    {
        "Name": "bridge",
        "Id": "17e324f459648a9baaea32b248d3884da102dde19396c25b30ec800068ce6b10",
        "Created": "2017-06-22T20:27:43.826654485Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "602dbf1edc81813304b6cf0a647e65333dc6fe6ee6ed572dc0f686a3307c6a2c": {
                "Name": "alpine2",
                "EndpointID": "03b6aafb7ca4d7e531e292901b43719c0e34cc7eef565b38a6bf84acf50f38cd",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "da33b7aa74b0bf3bda3ebd502d404320ca112a268aafe05b4851d1e3312ed168": {
                "Name": "alpine1",
                "EndpointID": "46c044a645d6afc42ddd7857d19e9dcfb89ad790afb5c239a35ac0af5e8a5bc5",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
複製代碼

在頂部附近,列出了有關橋接網絡的信息,包括Docker主機和橋接網絡之間的網關的IP地址(172.17.0.1)。 在Containers項下,列出了每一個鏈接的容器及其IP地址信息(lpine1172.17.0.2alpine2172.17.0.3

4.容器在後臺運行。 使用docker attach命令鏈接到alpine1

$ docker attach alpine1

/ #
複製代碼

提示符將更改成以指示您是容器中的root用戶。 使用ip addr show命令從容器中查看alpine1的網絡接口:

# ip addr show

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe11:2/64 scope link
       valid_lft forever preferred_lft forever
複製代碼

第一個接口是環回設備。如今先忽略它。注意,第二個接口的IP地址是172.17.0.2,這與前面步驟中顯示的alpine1的地址相同。

5.在alpine1內部,經過ping baidu.com確保您能夠鏈接到互聯網。 -c 2標誌將命令限制爲兩ping嘗試。

➜  ~ ping -c 2 baidu.com
PING baidu.com (39.156.69.79): 56 data bytes
64 bytes from 39.156.69.79: icmp_seq=0 ttl=46 time=34.887 ms
64 bytes from 39.156.69.79: icmp_seq=1 ttl=46 time=41.880 ms

--- baidu.com ping statistics ---
2 packets transmitted, 2 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 34.887/38.383/41.880/3.497 ms
➜  ~ 
複製代碼

6.如今嘗試ping第二個容器。 首先,經過其IP地址172.17.0.3對其執行ping操做:

# ping -c 2 172.17.0.3

PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.086 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.094 ms

--- 172.17.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.086/0.090/0.094 ms
複製代碼

這樣成功了。 接下來,嘗試按容器名稱ping alpine2容器。 這將失敗。

# ping -c 2 alpine2

ping: bad address 'alpine2'
複製代碼

7.經過使用分離序列CTRL + p CTRL + q(按住CTRL並鍵入p後跟q)從alpine1分離而不中止它。 若是願意,請附加到alpine2並在那裏重複步驟四、5和6,將alpine1代替爲alpine2

8.中止並刪除兩個容器。

$ docker container stop alpine1 alpine2
$ docker container rm alpine1 alpine2
複製代碼

請記住,不建議將默認網橋網絡用於生產。

使用用戶定義的橋接網絡

In this example, we again start two alpine containers, but attach them to a user-defined network called alpine-net which we have already created. These containers are not connected to the default bridge network at all. We then start a third alpine container which is connected to the bridge network but not connected to alpine-net, and a fourth alpine container which is connected to both networks. 在此示例中,咱們再次啓動兩個Alpine容器,可是將它們附加到咱們已經建立的名爲alpine-net的用戶定義網絡上。 這些容器根本沒有鏈接到默認橋接網絡。 而後,咱們啓動鏈接到默認網橋網絡但未鏈接alpine-net的第三個alpine容器,以及鏈接到兩個網絡的第四個alpine容器。

1.建立 alpine-net網絡. 你不須要指定--driver bridge標籤由於它是默認的,但本實例展現瞭如何指定它:

$ docker network create --driver bridge alpine-net
複製代碼

2.列出Docker網絡

$ docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
e9261a8c9a19        alpine-net          bridge              local
17e324f45964        bridge              bridge              local
6ed54d316334        host                host                local
7092879f2cc8        none                null                local
複製代碼

檢查alpine-net網絡。這顯示了它的IP地址,以及沒有容器鏈接到它的事實.

$ docker network inspect alpine-net

[
    {
        "Name": "alpine-net",
        "Id": "e9261a8c9a19eabf2bf1488bf5f208b99b1608f330cff585c273d39481c9b0ec",
        "Created": "2017-09-25T21:38:12.620046142Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
複製代碼

請注意,該網絡的網關是172.18.0.1,而默認網橋網絡的網關是172.17.0.1。 您系統上的確切IP地址可能不一樣。

3.建立你的第四個容器,注意--network選項。在docker run命令中你只能鏈接到一個網絡。因此,你須要使用docker network connect命令將第四個容器鏈接到默認橋接網絡上。

$ docker run -dit --name alpine1 --network alpine-net alpine ash

$ docker run -dit --name alpine2 --network alpine-net alpine ash

$ docker run -dit --name alpine3 alpine ash

$ docker run -dit --name alpine4 --network alpine-net alpine ash

$ docker network connect bridge alpine4
複製代碼

驗證全部容器都在運行:

$ docker container ls

CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
156849ccd902        alpine              "ash"               41 seconds ago       Up 41 seconds                           alpine4
fa1340b8d83e        alpine              "ash"               51 seconds ago       Up 51 seconds                           alpine3
a535d969081e        alpine              "ash"               About a minute ago   Up About a minute                       alpine2
0a02c449a6e9        alpine              "ash"               About a minute ago   Up About a minute                       alpine1
複製代碼

4.再次檢查默認網橋網絡和alpine-net網:

$ docker network inspect bridge

[
    {
        "Name": "bridge",
        "Id": "17e324f459648a9baaea32b248d3884da102dde19396c25b30ec800068ce6b10",
        "Created": "2017-06-22T20:27:43.826654485Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "156849ccd902b812b7d17f05d2d81532ccebe5bf788c9a79de63e12bb92fc621": {
                "Name": "alpine4",
                "EndpointID": "7277c5183f0da5148b33d05f329371fce7befc5282d2619cfb23690b2adf467d",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "fa1340b8d83eef5497166951184ad3691eb48678a3664608ec448a687b047c53": {
                "Name": "alpine3",
                "EndpointID": "5ae767367dcbebc712c02d49556285e888819d4da6b69d88cd1b0d52a83af95f",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
複製代碼

alpine3alpine4 容器鏈接到了默認的橋接網絡

$ docker network inspect alpine-net

[
    {
        "Name": "alpine-net",
        "Id": "e9261a8c9a19eabf2bf1488bf5f208b99b1608f330cff585c273d39481c9b0ec",
        "Created": "2017-09-25T21:38:12.620046142Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "0a02c449a6e9a15113c51ab2681d72749548fb9f78fae4493e3b2e4e74199c4a": {
                "Name": "alpine1",
                "EndpointID": "c83621678eff9628f4e2d52baf82c49f974c36c05cba152db4c131e8e7a64673",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "156849ccd902b812b7d17f05d2d81532ccebe5bf788c9a79de63e12bb92fc621": {
                "Name": "alpine4",
                "EndpointID": "058bc6a5e9272b532ef9a6ea6d7f3db4c37527ae2625d1cd1421580fd0731954",
                "MacAddress": "02:42:ac:12:00:04",
                "IPv4Address": "172.18.0.4/16",
                "IPv6Address": ""
            },
            "a535d969081e003a149be8917631215616d9401edcb4d35d53f00e75ea1db653": {
                "Name": "alpine2",
                "EndpointID": "198f3141ccf2e7dba67bce358d7b71a07c5488e3867d8b7ad55a4c695ebb8740",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
複製代碼

alpine1, alpine2, 和 alpine4容器鏈接到了alpine-net 網絡.

5。在像alpine-net這樣的用戶定義網絡上,容器不只能夠按IP地址進行通訊,並且還能夠將容器名稱解析爲IP地址。 此功能稱爲自動服務發現。 讓咱們鏈接到alpine1並進行測試。 alpine1應該可以將alpine2alpine4(以及alpine1自己)解析爲IP地址。

$ docker container attach alpine1

# ping -c 2 alpine2

PING alpine2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.085 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.090 ms

--- alpine2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.085/0.087/0.090 ms

# ping -c 2 alpine4

PING alpine4 (172.18.0.4): 56 data bytes
64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.076 ms
64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.091 ms

--- alpine4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.076/0.083/0.091 ms

# ping -c 2 alpine1

PING alpine1 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.026 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.054 ms

--- alpine1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.026/0.040/0.054 ms

複製代碼

6.從 alpine1, 你沒法鏈接到alpine3, 由於它不在alpine-net網內.

# ping -c 2 alpine3

ping: bad address 'alpine3'
複製代碼

不只如此,你也不能經過它的IP地址從alpine1鏈接到alpine3。查看docker network inspect的輸出,找到alpine3的IP地址:172.17.0.2,試着ping它。

# ping -c 2 172.17.0.2

PING 172.17.0.2 (172.17.0.2): 56 data bytes

--- 172.17.0.2 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
複製代碼

使用分離序列CTRL + p CTRL + q(按住CTRL並鍵入p後跟q)從alpine1分離。

7.請記住,alpine4已鏈接到默認網橋網絡和alpine-net。 它應該可以到達全部其餘容器。 可是,您將須要按其IP地址尋址alpine3。 附加到它並運行測試。

$ docker container attach alpine4

# ping -c 2 alpine1

PING alpine1 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.074 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.082 ms

--- alpine1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.074/0.078/0.082 ms

# ping -c 2 alpine2

PING alpine2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.075 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.080 ms

--- alpine2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.075/0.077/0.080 ms

# ping -c 2 alpine3
ping: bad address 'alpine3'

# ping -c 2 172.17.0.2

PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.089 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.075 ms

--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.075/0.082/0.089 ms

# ping -c 2 alpine4

PING alpine4 (172.18.0.4): 56 data bytes
64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.033 ms
64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.064 ms

--- alpine4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.033/0.048/0.064 ms

複製代碼

8.做爲最後一個測試,經過ping www.baidu.com確保全部的容器均可以鏈接到網絡.由於當前你已經鏈接到了alpine4,就從它開始,而後退出alpine4並鏈接到alpine3 (該容器僅僅鏈接到默認的橋接網絡) 進行重試。最後鏈接到alpine1 (它僅僅鏈接到alpine-net網絡)並進行重試.

# ping -c 2 baidu.com

PING baidu.com (172.217.3.174): 56 data bytes
64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.778 ms
64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.634 ms

--- baidu.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 9.634/9.706/9.778 ms

CTRL+p CTRL+q

$ docker container attach alpine3

# ping -c 2 baidu.com

PING baidu.com (172.217.3.174): 56 data bytes
64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.706 ms
64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.851 ms

--- baidu.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 9.706/9.778/9.851 ms

CTRL+p CTRL+q

$ docker container attach alpine1

# ping -c 2 baidu.com

PING baidu.com (172.217.3.174): 56 data bytes
64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.606 ms
64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.603 ms

--- baidu.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 9.603/9.604/9.606 ms

CTRL+p CTRL+q

複製代碼

9.最後中止並刪除全部容器並刪除alpine-net網絡

$ docker container stop alpine1 alpine2 alpine3 alpine4

$ docker container rm alpine1 alpine2 alpine3 alpine4

$ docker network rm alpine-net
複製代碼

overlay network聯網

本系列教程討論集羣服務的網絡。本主題包含四個部份內容,你能夠在不一樣的平臺上運行他們,可是對於最後兩個,你須要一個額外的Docker主機。

  • 使用默認overlay network演示瞭如何在初始化或加入羣集時使用Docker自動爲您設置的默認的overlay network。 該網絡不是生產系統的最佳選擇。
  • 使用用戶定義的overlay network顯示瞭如何建立和使用本身的自定義overlay network來鏈接服務。 建議將其用於生產中運行的服務。
  • overlay network用於獨立容器顯示瞭如何使用overlay network在不一樣Docker守護程序上的獨立容器之間進行通訊。
  • 容器與羣集服務之間的通訊使用可鏈接的overlay network在獨立容器與羣集服務之間創建通訊。 Docker 17.06及更高版本支持此功能。

準備工做

這些要求您至少有一個單節點羣集,這意味着您已啓動Docker並在主機上運行docker swarm init。 您也能夠在多節點集羣上運行示例。 最後一個示例須要Docker 17.06或更高版本。

使用默認的overlay network

在本例中,您啓動一個alpine服務,並從各個服務容器的角度分析網絡的特徵。

本教程不討論有關如何實現overlay network的特定於操做系統的詳細信息,而是重點關注從服務的角度來看,overlay network是如何工做的。

準備

本教程須要三臺物理或虛擬Docker主機,它們能夠相互通訊,而且都運行Docker 17.03或更高版本的新安裝。 本教程假定這三臺主機在同一網絡上運行,而且不涉及防火牆。

這些主機將被稱爲manager, worker-1,worker-2.manager主機即做爲管理者又做爲工做者,這意味着它既要運行服務任務,也要管理swarm. worker-1worker-2 將僅做爲工做者。

若是您沒有三臺主機,一個簡單的解決方案是在雲提供商(例如Amazon EC2)上設置三臺Ubuntu主機,它們所有位於同一網絡上,並容許與該網絡上的全部主機進行全部通訊(使用諸如 EC2安全組),而後按照Ubuntu上Docker Engine-Community的安裝說明進行操做。

演示

建立swarm

在此過程結束時,全部三個Docker主機都將加入集羣,並使用稱爲ingress的覆蓋網絡鏈接在一塊兒.

1.在manager上,初始化swarm集羣。若是主機只有一個網絡接口,--advertise-addr 選項是可選的。

$ docker swarm init --advertise-addr=<IP-ADDRESS-OF-MANAGER>
複製代碼

記下所打印的文本,由於其中包含將用於將worker-1和worker-2加入到羣中的令牌。 將令牌存儲在密碼管理器中是一個好主意。

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上, 列出全部的節點。這個命令只能在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-1,worker-2上全部的網絡,請注意它們如今都有一個叫作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主機的網絡接口,以便流量能夠往返於羣管理者和工做者。若是建立羣集服務但未指定網絡,則它們將鏈接到ingress網絡.建議對將一塊兒使用的每一個應用程序或一組應用程序使用單獨的覆蓋網絡。在下一個過程當中,您將建立兩個覆蓋網絡並將服務鏈接到每一個覆蓋網絡。

建立服務

1.在manager上,建立一個新的overlay network叫nginx-net:

$ docker network create -d overlay nginx-net
複製代碼

您無需在其餘節點上建立overlay網絡,由於當其中一個節點開始運行須要該overlay網絡的服務任務時,overlay網絡會自動建立。

2.在manager上, 建立一個有5個副本的Nginx服務並鏈接到nginx-net.服務將對外開放80端口。全部服務任務容器均可以在不打開任何端口的狀況下彼此通訊。

服務只能在管理器上建立

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

ingress的默認發佈模式, 在你沒有爲--publish選項指定一個mode時使用。這意味着你若是訪問manager,worker-1或者worker-2上的80端口,你將鏈接到5個服務任務中的任何一個的80端口上。即使當前並無任務運行在你訪問的節點上。若是你想使用host模式發佈端口,你能夠在--publish選項上增長mode=host。可是,這種狀況下,你要用--mode global代替 --replicas=5, 由於只有一個服務任務能夠綁定到給定節點上的給定端口。

3.運行docker service ls監視服務啓動進度,這可能須要幾秒鐘。

4.在manage,worker-1,worker-2上檢查nginx-net網絡. 記住你不須要在worker-1worker-2上手動建立它,由於Docker會給你建立好。輸出會很長,可是隻需注意ContainersPeers部分。Containers列出了全部的從該主機鏈接到overlay網絡的服務任務(或者單獨的容器)。

5.對於manager,使用docker service inspect my-nginx檢查服務,並注意有關服務使用的端口和端點的信息。

6.建立一個新的網絡nginx-net-2, 而後使用這個新的網絡更新服務:

$ 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運行相同的命令,注意全部的服務任務容器都鏈接到它。

overlay網絡在swarn工做節點上是按需自動建立的,他們不會自動刪除

8.清理服務和網絡。 在管理器中,運行如下命令。 管理者將指示工做人員自動刪除網絡。

$ docker service rm my-nginx
$ docker network rm nginx-net nginx-net-2
複製代碼

使用用戶自定義的overlay網絡

準備

本教程假設羣集已經設置好,而且您是在一個管理器上。

演示

1.建立用戶定義的覆蓋網絡。

$ docker network create -d overlay my-overlay
複製代碼

2.使用overlay網絡啓動一個服務並將端口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
複製代碼

在獨立容器上使用overlay網絡

此示例演示了DNS容器發現-具體地說,是如何使用覆蓋網絡在不一樣Docker守護程序上的獨立容器之間進行通訊。 步驟以下:

  • host1上, 初始化節點爲一個swarm(manager).
  • host2上, 加入該節點到swarm中(做爲工做節點)
  • host1上,建立一個可鏈接的覆蓋網絡(test-net)。
  • host1上,在test-net上運行一個交互式alpine容器 (alpine1)。
  • host2上,在test-net上運行一個交互式,可分離的alpine容器 (alpine2)。
  • host1上, 從一個alpine1會話中,ping alpine2

準備

對於此測試,您須要兩個能夠相互通訊的不一樣Docker主機。 每一個主機必須具備Docker 17.06或更高版本,而且在兩個Docker主機之間打開如下端口:

  • TCP port 2377
  • TCP and UDP port 7946
  • UDP port 4789

一種簡單的設置方法是擁有兩個VM(本地或在AWS等雲提供商上),每一個VM均已安裝並正在運行Docker。 若是您使用的是AWS或相似的雲計算平臺,最簡單的配置是使用一個安全組,該安全組打開兩個主機之間的全部傳入端口以及來自客戶端IP地址的SSH端口。

此示例將咱們羣中的兩個節點稱爲host1host2。 此示例還使用Linux主機,可是相同的命令在Windows上也可使用。

演示

1.設置swarm 在host1上,初始化集羣(若是出現提示,請使用--advertise-addr指定與集羣中其餘主機通訊的接口的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.
複製代碼

host2上,按照上述說明加入羣集:

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

若是節點沒法加入羣集,則docker swarm join命令會超時。 要解決此問題,請在host2上運行docker swarm leave --force,驗證您的網絡和防火牆設置,而後重試。

2.在host1上, 建立一個能夠鏈接的overlay網絡叫test-net:

$ docker network create --driver=overlay --attachable test-net
uqsof8phj3ak0rq9k86zta6ht
複製代碼

注意返回的NETWORK ID-從host2鏈接到它時,您將再次看到它。

3.在host1上,啓動一個交互式的容器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.On 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容器,而不detached.你能夠從host2ping 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就會消失。

host2上,中止alpine2,檢查test-net已經刪除,而後刪除alpine2:

$ docker container stop alpine2
$ docker network ls
$ docker container rm alpine2
複製代碼

host1上, 刪除 alpine1 and test-net:

$ docker container rm alpine1
$ docker network rm test-net
複製代碼

在容器和集羣服務之間進行通訊

準備

本例須要Docker 17.06或更高版本。

演示

在此示例中,您在同一Docker主機上啓動了兩個不一樣的alpine1容器,並進行了一些測試以瞭解它們如何相互通訊。 您須要安裝並運行Docker。

1.打開一個終端窗口。 在執行其餘任何操做以前,請先列出當前網絡。 若是您從未在此Docker守護程序上添加網絡或初始化羣組,則應該看到如下內容。 您可能會看到不一樣的網絡,但至少應該看到如下內容(網絡ID會有所不一樣):

$ docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
17e324f45964        bridge              bridge              local
6ed54d316334        host                host                local
7092879f2cc8        none                null                local
複製代碼

列出了默認的橋接網絡,以及hostnone。 後兩個不是徹底成熟的網絡,但用於啓動直接鏈接到Docker守護程序主機的網絡堆棧的容器,或用於啓動不包含網絡設備的容器。 本教程將把兩個容器鏈接到橋接網絡。

2.啓動兩個運行ash的Alpine容器,這是Alpine的默認shell,而不是bash-dit標誌的意思是啓動分離的容器(在後臺),交互的(具備鍵入的能力)和TTY(以便您能夠看到輸入和輸出)。 因爲您是分開啓動的,所以您不會當即鏈接到該容器。 而是將打印容器的ID。 由於您未指定任何--network標誌,因此容器將鏈接到默認的網橋網絡。

$ docker run -dit --name alpine1 alpine ash

$ docker run -dit --name alpine2 alpine ash
複製代碼

檢查兩個容器是否確實已啓動:

$ docker container ls

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
602dbf1edc81        alpine              "ash"               4 seconds ago       Up 3 seconds                            alpine2
da33b7aa74b0        alpine              "ash"               17 seconds ago      Up 16 seconds                           alpine1
複製代碼

3.檢查網橋網絡以查看鏈接了哪些容器。

$ docker network inspect bridge

[
    {
        "Name": "bridge",
        "Id": "17e324f459648a9baaea32b248d3884da102dde19396c25b30ec800068ce6b10",
        "Created": "2017-06-22T20:27:43.826654485Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "602dbf1edc81813304b6cf0a647e65333dc6fe6ee6ed572dc0f686a3307c6a2c": {
                "Name": "alpine2",
                "EndpointID": "03b6aafb7ca4d7e531e292901b43719c0e34cc7eef565b38a6bf84acf50f38cd",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "da33b7aa74b0bf3bda3ebd502d404320ca112a268aafe05b4851d1e3312ed168": {
                "Name": "alpine1",
                "EndpointID": "46c044a645d6afc42ddd7857d19e9dcfb89ad790afb5c239a35ac0af5e8a5bc5",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
複製代碼

在頂部附近,列出了有關橋接網絡的信息,包括Docker主機和橋接網絡之間的網關的IP地址(172.17.0.1)。 在Containers項下,列出了每一個鏈接的容器及其IP地址信息(alpine1172.17.0.2alpine2172.17.0.3)。

4.容器在後臺運行。 使用docker attach命令鏈接到alpine1

$ docker attach alpine1

/ #
複製代碼

提示符將更改成以指示您是容器中的root用戶。 使用ip addr show命令從容器中查看alpine1的網絡接口:

# ip addr show

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe11:2/64 scope link
       valid_lft forever preferred_lft forever
複製代碼

第一個接口是環回設備。如今先忽略它。注意,第二個接口的IP地址是172.17.0.2,這與前面步驟中顯示的alpine1的地址相同。

5.在alpine1內部,經過ping baidu.com確保您能夠鏈接到互聯網。-c 2標誌將命令限制兩次兩次ping操做。

# ping -c 2 baidu.com

PING baidu.com (172.217.3.174): 56 data bytes
64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.841 ms
64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.897 ms

--- baidu.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 9.841/9.869/9.897 ms
複製代碼

7.如今嘗試ping第二個容器。 首先,經過其IP地址172.17.0.3對其執行ping操做:

# ping -c 2 172.17.0.3

PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.086 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.094 ms

--- 172.17.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.086/0.090/0.094 ms
複製代碼

這樣成功了。 接下來,嘗試按容器名稱ping alpine2容器。 這將失敗。

# ping -c 2 alpine2

ping: bad address 'alpine2'
複製代碼

7.經過使用分離序列CTRL + p CTRL + q(按住CTRL並鍵入p後跟q)從alpine1分離而不中止它。 若是願意,請附加到alpine2並在那裏重複步驟四、5和6,將alpine1代替爲alpine2

8.中止並刪除容器;

$ docker container stop alpine1 alpine2
$ docker container rm alpine1 alpine2
複製代碼

請記住,不建議將默認網橋網絡用於生產。

相關文章
相關標籤/搜索