Home >> Blog >> 了解 docker network

了解 docker network

Docker 是當今大多數企業組織中大規模構建和運行容器的事實模型。在非常高的層次上,Docker 是 CLI 和守護進程的組合,可以解決常見的軟體問題,例如安裝、發布、刪除和管理容器。它非常適合微服務例如執行SEO搜尋引擎優化的email服務即可使用docker,您有許多服務處理典型的業務功能;Docker 使打包更容易,使您能夠將這些服務封裝在容器中。

一旦應用程式位於容器中,就更容易擴展,甚至可以在不同的雲平台上運行,如 AWS、GCP 和 Azure。在本文中,讓我們關注Docker 的網路方面。

什麼是 Docker 網路?

網路是關於進程之間的通信,Docker 的網路也不例外。Docker 網路主要用於通過運行 Docker 守護進程的主機在 Docker 容器和外部世界之間建立通信。

Docker 支持不同類型的網路,每種都適合特定的用例。我們將探索 Docker 一般支持的網路驅動程式,以及一些編碼示例。

Docker 網路在以下幾個方面不同於虛擬機 (VM) 或物理機網路:

  1. 虛擬機在某些方面更加靈活,因為它們可以支持NAT 和主機網路等配置。Docker 通常使用橋接網路,雖然它可以支持主機網路,但該選項僅在 Linux 上可用。
  2. 使用 Docker 容器時,網路隔離是使用網路命名空間實現的,而不是完全獨立的網路堆棧。
  3. 您可以在單節點 Docker 主機上運行數百個容器,因此要求主機能夠支持這種規模的網路。VM 通常不會遇到這些網路限制,因為它們通常每個 VM 運行的進程較少。

什麼是 Docker 網路驅動程式?

Docker 通過創建默認的橋接網路來處理容器之間的通信,因此您通常不必處理網路問題,而可以專注於創建和運行容器。此默認橋接網路在大多數情況下都有效,但它不是您擁有的唯一選擇。

Docker 允許您開箱即用地創建三種不同類型的網路驅動程式:橋接、主機和無。但是,它們可能並不適合所有用例,因此我們還將探索用戶定義的網路,例如overlay和macvlan。讓我們仔細看看每一個。

橋樑司機

這是默認設置。每當您啟動 Docker 時,都會創建一個橋接網路,並且所有新啟動的容器都會自動連接到默認的橋接網路。

每當您希望您的容器獨立運行以相互連接和通信時,您都可以使用它。由於容器是獨立運行的,橋接網路解決了端口衝突問題。運行在同一個橋接網路中的容器可以相互通信,Docker使用宿主機上的iptables來防止橋接之外的訪問。

讓我們看一些橋接網路驅動程式如何工作的示例。

  1. docker network ls通過運行命令檢查可用網路
  2. 通過傳遞標誌啟動兩個名為並處於分離模式的busybox容器。busybox1busybox2-dit

$ docker network ls
NETWORK ID NAME DRIVER SCOPE
5077a7b25ae6 bridge bridge local
7e25f334b07f host host local
475e50be0fe0 none null local
docker run -dit --name busybox1 busybox /bin/sh
docker run -dit --name busybox2 busybox /bin/sh

3.運行docker ps命令以驗證容器是否已啟動並正在運行。

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9e6464e82c4c busybox "/bin/sh" 5 seconds ago Up 5 seconds busybox2
7fea14032748 busybox "/bin/sh" 26 seconds ago Up 26 seconds


4.驗證容器是否已連接到橋接網路。

$ docker network inspect bridge
[
{
"Name": "bridge",
"Id": "5077a7b25ae67abd46cff0fde160303476c8a9e2e1d52ad01ba2b4bf04acc0e0",
"Created": "2021-03-05T03:25:58.232446444Z",
"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,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"7fea140327487b57c3cf31d7502cfaf701e4ea4314621f0c726309e396105885": {

"Name": "busybox1",

"EndpointID": "05f216032784786c3315e30b3d54d50a25c1efc7d2030dc664716dda38056326",

"MacAddress": "02:42:ac:11:00:02",

"IPv4Address": "172.17.0.2/16",

"IPv6Address": ""

},

"9e6464e82c4ca647b9fb60a85ca25e71370330982ea497d51c1238d073148f63": {

"Name": "busybox2",

"EndpointID": "3dcc24e927246c44a2063b5be30b5f5e1787dcd4d53864c6ff2bb3c561519115",

"MacAddress": "02:42:ac:11:00:03",

"IPv4Address": "172.17.0.3/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": {}
}
]

5.在容器的鍵下,您可以觀察到兩個容器 (busybox1和busybox2) 列出了有關 IP 地址的資訊。由於容器在後台運行,因此附加到busybox1容器並嘗試busybox2使用其 IP 地址 ping。

$ docker attach busybox1
/ # whoami
root
/ # hostname -i
172.17.0.2
/ # ping 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=2.083 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.144 ms
/ # ping busybox2
ping: bad address 'busybox2'


6.觀察到 ping 通過傳遞的 IP 地址起作用,busybox2但在傳遞容器名稱時失敗。

橋驅動器的缺點是不推薦用於生產。容器通過 IP 地址而不是自動服務發現進行通信,以將 IP 地址解析為容器名稱。每次運行容器時,都會為其分配一個不同的 IP 地址。它可能適用於本地開發或 CI/CD,但對於在生產中運行的應用程式來說,它絕對不是一種可持續的方法。

另一個不在生產環境中使用它的原因是它允許不相關的容器相互通信,這可能是一個安全風險。稍後我將介紹如何創建自定義橋接網路。

主機驅動程式

顧名思義,主機驅動程式使用主機提供的網路。它消除了容器和運行 Docker 的主機之間的網路隔離。例如,如果您運行一個綁定到端口 80 並使用主機網路的容器,則容器的應用程式在主機 IP 地址的端口 80 上可用。如果您不想依賴 Docker 的網路而是依賴主機網路,則可以使用主機網路。

主機驅動程式的一個限制是它不能在 Docker 桌面上運行:您需要一個 Linux 主機才能使用它。本文重點介紹 Docker 桌面,但我將向您展示使用 Linux 主機所需的命令。

以下命令將啟動 Nginx 映像並偵聽主機上的 80 端口:

docker run --rm -d --network host --name my_nginx nginx

您可以通過點擊http://localhost:80/ url.

主機網路的缺點是您不能在具有相同端口的同一主機上運行多個容器。端口由主機網路上的所有容器共享。

no driver

none 網路驅動程式不會將容器附加到任何網路。容器不訪問外部網路或與其他容器通信。當你想禁用容器上的網路時,你可以使用它。

覆蓋驅動程式

Overlay 驅動程式用於多主機網路通信,與Docker Swarm或Kubernetes 一樣。它允許跨主機的容器相互通信,而無需擔心設置。將覆蓋網路視為構建在現有計算機網路之上的分佈式虛擬化網路。

要為 Docker Swarm 服務創建覆蓋網路,請使用以下命令:

docker network create -d overlay my-overlay-network

要創建覆蓋網路以便獨立容器可以相互通信,請使用以下命令:

docker network create -d overlay --attachable my-attachable-overlay

基本的 Docker 網路命令

要查看哪些命令列出、創建、連接、斷開、檢查或刪除 Docker 網路,請使用該docker network help命令。

$ docker network help

Usage: docker network COMMAND

Manage networks

Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks


讓我們看一下每個命令的一些示例,從docker network connect.

將容器連接到網路

讓我們嘗試將一個容器連接到mynetwork我們創建的容器。首先,我們需要一個可以連接到mynetwork.

$ docker run -it ubuntu bash
root@0f8d7a833f42:/#

現在我們有了一個 Ubuntu Linux 映像,並在其中以 root 身份啟動了一個登錄 shell。-it我們讓容器在標誌的幫助下以交互模式運行。

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0f8d7a833f42 ubuntu "bash" 9 seconds ago Up 7 seconds wizardly_greider

運行docker network connect 0f8d7a833f42命令連接名為 . 的wizardly_greider容器mynetwork。要驗證此容器是否已連接到mynetwork,請使用該docker inspect命令

"mynetwork": {
"IPAMConfig": {},
"Links": null,
"Aliases": [ "0f8d7a833f42"
],
"NetworkID": "97a158252c995d3632560852c62bd140984769c8714b1f990c8133a5c8ae65d3",
"EndpointID": "db21f395ca781523c115706b11063ebe879cf5ef246c24fd128fe621a582cade",
"Gateway": "172.20.0.1",
"IPAddress": "172.20.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:14:00:02",
"DriverOpts": {}
}

創建網路

您可以使用它docker network create mynetwork來創建 Docker 網路。在這裡,我們創建了一個名為mynetwork. 讓我們運行docker network ls來驗證網路是否創建成功。

$ docker network ls
NETWORK ID NAME DRIVER SCOPE
b995772ac197 bridge bridge local
7e25f334b07f host host local
97a158252c99 mynetwork bridge local
475e50be0fe0 none null local


現在我們有了一個名為 的新自定義網路mynetwork,它的類型是橋接。

斷開容器與網路的連接

此命令將 Docker 容器與自定義斷開連接mynetwork:

docker network disconnect mynetwork 0f8d7a833f42

檢查網路

該docker network inspect命令顯示一個或多個網路的詳細資訊。

$ docker network inspect mynetwork
[
{
"Name": "mynetwork",
"Id": "97a158252c995d3632560852c62bd140984769c8714b1f990c8133a5c8ae65d3",
"Created": "2021-03-02T17:36:30.090173896Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.20.0.0/16",
"Gateway": "172.20.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"0f8d7a833f4283202e905e621e6fd5b29a8e3d4eccc6be6ea0f209f5cb3ca81c": {
"Name": "wizardly_greider",
"EndpointID": "db21f395ca781523c115706b11063ebe879cf5ef246c24fd128fe621a582cade",
"MacAddress": "02:42:ac:14:00:02",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]


列出可用網路

Docker 安裝附帶三個網路:none、bridge 和 host。您可以通過運行以下命令來驗證這一點docker network ls:

docker network ls
NETWORK ID NAME DRIVER SCOPE
b995772ac197 bridge bridge local
7e25f334b07f host host local
475e50be0fe0 none null local


刪除網路

以下是刪除特定或所有可用網路的 Docker 命令:

$ docker network rm mynetwork
mynetwork
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
b995772ac197 bridge bridge local
7e25f334b07f host host local
475e50be0fe0 none null local


$ docker network prune
WARNING! This will remove all custom networks not used by at least one container.
Are you sure you want to continue? [y/N]


公共網路

下面講講如何向外界發布一個容器的端口和IP地址。當您使用該命令啟動容器時docker run,它的任何端口都不會暴露。你的 Docker 容器可以連接到外界,但是外界無法連接到容器。要使端口可訪問以供外部使用或與不在同一網路上的其他容器一起使用,您必須使用-P(發布所有可用端口)或-p(發布特定端口)標誌。

例如,這裡我們將容器的 TCP 端口 80 映射到 Docker 主機上的端口 8080:

docker run -it --rm nginx -p 8080:80

在這裡,我們將容器 TCP 端口 80 映射到 Docker 主機上的端口 8080,以連接到主機 IP 192.168.1.100:

docker run -p 192.168.1.100:8085:80 nginx

您可以通過運行以下 curl 命令來驗證這一點:

$ curl 192.168.1.100:8085
< !DOCTYPE html>
< html>
< head>
< title>Welcome to nginx!< /title>
< style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
< /style>
< /head>
< body>
< h1>Welcome to nginx!< /h1>
< p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.< /p>

< p>For online documentation and support please refer to
< a href="http://nginx.org/">nginx.org< /a>.< br/>
Commercial support is available at
< a href="http://nginx.com/">nginx.com< /a>.< /p>

< p>< em>Thank you for using nginx.< /em>< /p>
< /body>
< /html>


讓我簡單提一下容器的 DNS 配置。Docker 為您的容器提供了進行基本名稱解析的能力:

$ docker exec busybox2 ping www.google.com
PING www.google.com (216.58.216.196): 56 data bytes
64 bytes from 216.58.216.196: seq=0 ttl=37 time=9.672 ms
64 bytes from 216.58.216.196: seq=1 ttl=37 time=6.110 ms
$ ping www.google.com
PING www.google.com (216.58.216.196): 56 data bytes
64 bytes from 216.58.216.196: icmp_seq=0 ttl=118 time=4.722 ms


Docker 容器在使用橋接網路時會從主機繼承 DNS 設置,因此默認情況下容器會像主機一樣解析 DNS 名稱。要將自定義主機記錄添加到您的容器,您需要使用此處列出的相關--dns*標誌。

Docker 撰寫網路

Docker Compose是一個用於在 Docker 上運行多容器應用程式的工具,這些應用程式是使用 compose YAML 文件定義的。您可以使用一個命令啟動您的應用程式:docker-compose up.

默認情況下,Docker Compose 為 compose 文件中定義的每個容器創建一個網路。compose 文件中定義的所有容器都通過默認網路連接和通信。

如果您不確定 Docker Compose 支持的命令,可以運行以下命令:

$ docker compose help
Docker Compose

Usage:
docker compose [command]

Available Commands:
build Build or rebuild services
convert Converts the compose file to a cloud format (default: cloudformation)
down Stop and remove containers, networks
logs View output from containers
ls List running compose projects
ps List containers
pull Pull service images
push Push service images
run Run a one-off command on a service
.
up Create and start containers

Flags:
-h, --help help for compose

Global Flags:
--config DIRECTORY Location of the client config files DIRECTORY (default "/Users/ashish/.docker")
-c, --context string context
-D, --debug Enable debug output in the logs
-H, --host string Daemon socket(s) to connect to

Use "docker compose [command] --help" for more information about a command.


讓我們通過一個例子來理解這一點。在以下docker-compose.yaml文件中,我們有一個 WordPress 和一個 MySQL 圖像。

部署此設置時,docker-compose將 WordPress 容器端口 80 映射到 compose 文件中指定的主機端口 80。我們尚未定義任何自定義網路,因此它應該為您創建一個。運行docker-compose up -d以調出 YAML 文件中定義的服務:

version: '3.7'
services:
db:
image: mysql:8.0.19
command: '--default-authentication-plugin=mysql_native_password'
restart: always
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
- MYSQL_ROOT_PASSWORD=somewordpress
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=wordpress
wordpress:
image: wordpress:latest
ports:
- 80:80
restart: always
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=wordpress
- WORDPRESS_DB_NAME=wordpress
volumes:
db_data:


正如您在以下輸出中看到的,downloads_default為您創建了一個名為的網路:

$ docker-compose up -d
Creating network "downloads_default" with the default driver
Creating volume "downloads_db_data" with default driver
Pulling db (mysql:8.0.19)...


使用以下命令驗證我們是否啟動並運行了兩個容器docker ps:

T$ docker psbr> CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESbr> f68265cd6219 wordpress:latest "docker-entrypoint.s…" 6 minutes ago Up 6 minutes 0.0.0.0:80->80/tcp downloads_wordpress_1br> 2838f5586c73 mysql:8.0.19 "docker-entrypoint.s…" 6 minutes ago Up 6 minutes 3306/tcp, 33060/tcp downloads_db_1

br>

在您的網路瀏覽器中導航到http://localhost:80以訪問 WordPress。

docker network inspect現在讓我們用命令檢查這個網路。以下是輸出:

$ docker network inspect downloads_default
[
{
"Name": "downloads_default",
"Id": "717ea814aae357ceca3972342a64335a0c910455abf160ed820018b8d6690383",
"Created": "2021-03-05T03:43:42.541707419Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"2838f5586c735894051498c8ed0e5e103209cd22ee5718cbb29e8c6d169c9bf8": {
"Name": "downloads_db_1",
"EndpointID": "10033e064387892253d69ac5813be6bc820a95df1a3e19f84eff99a8d55af1bd",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
},
"f68265cd6219fb60491c7ebbdae2d7f4c5ea4a74aec9987f5a5082c13b1ec025": {
"Name": "downloads_wordpress_1",
"EndpointID": "a4a673479ab3d812713955d461cc4d7032aba3806b49f50dd783a8083588aec5",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {
"com.docker.compose.network": "default",
"com.docker.compose.project": "downloads",
"com.docker.compose.version": "1.27.4"
}
}
]


在容器部分,您可以看到兩個容器(downloads_db_1和downloads_wordpress_1)附加到默認downloads_default網路驅動程式,即橋接類型。運行以下命令來清理所有內容:

$ docker-compose down
Stopping downloads_wordpress_1 ... done
Stopping downloads_db_1 ... done
Removing downloads_wordpress_1 ... done
Removing downloads_db_1 ... done
Removing network downloads_default


您可以觀察到 Compose 創建的網路也被刪除了:

$ docker-compose down -v
Removing network downloads_default
WARNING: Network downloads_default not found.
Removing volume downloads_db_data


之前創建的捲被刪除了,由於運行上一條命令後網路已經被刪除,所以會提示找不到默認網路。沒關係。

到目前為止,我們看到的示例涵蓋了 Compose 創建的默認網路,但是如果我們想要創建自定義網路並將服務連接到它怎麼辦?您將使用 Compose 文件定義用戶定義的網路。以下是docker-composeYAML 文件:

version: '3.7'
services:

db:

image: mysql:8.0.19

command: '--default-authentication-plugin=mysql_native_password'

restart: always

volumes:

- db_data:/var/lib/mysql

restart: always

networks:

- mynetwork

environment:

- MYSQL_ROOT_PASSWORD=somewordpress

- MYSQL_DATABASE=wordpress

- MYSQL_USER=wordpress

- MYSQL_PASSWORD=wordpress

wordpress:

image: wordpress:latest

ports:

- 80:80

networks:

- mynetwork

restart: always

environment:

- WORDPRESS_DB_HOST=db

- WORDPRESS_DB_USER=wordpress

- WORDPRESS_DB_PASSWORD=wordpress

- WORDPRESS_DB_NAME=wordpress

volumes:
db_data:
networks:
mynetwork:


我在文件末尾的頂級網路部分下定義了一個用戶定義的網路,並將其命名為 network mynetwork。它是一種網橋類型,這意味著它是主機上的一個網路,與主機網路堆棧的其餘部分分開。在每個服務之後,我添加了網路密鑰以指定這些服務應連接到mynetwork.

讓我們在更改 Docker Compose YAML 文件後再次啟動服務:

$ docker-compose up -d
Creating network "downloads_mynetwork" with the default driver
Creating volume "downloads_db_data" with default driver
Creating downloads_wordpress_1 ... done
Creating downloads_db_1 ... done

如您所見,Docker Compose 創建了新的 custom mynetwork,啟動了容器,並將它們連接到自定義網路。您可以使用 Docker 檢查命令對其進行檢查:

$ docker network inspect downloads_mynetwork
[
{
"Name": "downloads_mynetwork",
"Id": "cb24ed3832dfdd34ca6fdcfcf0065c8e0df6b9b72f7b29a2aaada74970835dd1",
"Created": "2021-03-05T04:23:14.354570267Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.19.0.0/16",
"Gateway": "172.19.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"334bd5bf1689b067fa24705af0b6ab444976b288d25846349ce5b8f6914d8c19": {
"Name": "downloads_wordpress_1",
"EndpointID": "10674d2ddd9feb67c98e3c08fcf451f32bda58e96c9c256aee70a0487f6a4496",
"MacAddress": "02:42:ac:13:00:03",
"IPv4Address": "172.19.0.3/16",
"IPv6Address": ""
},
"9ffc94adab6896620648a1d08d215ba3d9423fee934b905b7bc2a44dd30bd74c": {
"Name": "downloads_db_1",
"EndpointID": "927943a0202bfb69692bc172a5c26e05676df6961236596eba3c3464cacbd1ab",
"MacAddress": "02:42:ac:13:00:02",
"IPv4Address": "172.19.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {
"com.docker.compose.network": "mynetwork",
"com.docker.compose.project": "downloads",
"com.docker.compose.version": "1.27.4"
}
}
]

檢查網路,您可以看到現在有兩個容器連接到自定義網路。

結論

在本文中,我們詳細介紹了 Docker 網路的內容和方式,從開箱即用的 Docker 網路驅動程式開始,然後是一些高級概念,例如 overlay 和 macvlan。我們瀏覽了一些最常見的 Docker 網路命令示例,然後討論了可用網路驅動程式的一些常見用例和一般缺陷。我們還介紹了端口發布,它允許外部世界與容器連接,以及 Docker 如何解析 DNS 名稱。最後,我們通過一些示例探索了 Docker Compose 網路。

這應該讓您對 Docker 網路如何提供不同模式的網路驅動程式有一個不錯的概述,以便您的容器可以在單主機或多主機設置上進行通信。有了這些知識,您就可以挑選適合您用例的網路驅動程式。