Docker 网络详解1

你是否曾经想过 Docker 中的网络是如何工作的?也许你对使用 Docker 的网络层可以做的鲜为人知的事情感兴趣?以下是一些有趣的事实和用例,可能有助于日常使用。

开放端口

让我们从基础开始。端口开放是 Docker 网络中最常用的东西,但你了解它的全部内容吗?

让我们看一个简单的命令,如下所示:

1
docker run -p 127.0.0.1:80:8080/tcp ubuntu bash

这是什么意思?好吧,可能有点棘手,但它的意思是:

在端口 80 上监听 127.0.0.1 上的 TCP 连接,并将流量转发到容器内的端口 8080

如果我们稍微简化一下:

1
docker run -p 80:8080/tcp ubuntu bash

我们省略了 IP 部分,现在 Docker 将监听所有接口,因此可以从外部访问该服务。

我们可以进一步更改符号,然后运行:

1
docker run -p 80:8080/udp ubuntu bash

这将转发 udp 连接。另一个选项是 sctp,但它并未广泛用于与 Web 相关的东西。TCP 显然是最常见的,因此如果我们跳过 /protocol 部分 - 它将默认设置为 TCP

如果我们只运行这个会发生什么:

1
docker run -p 8080 ubuntu bash

这会将 TCP 流量从随机选择的端口转发到容器中的端口 8080。等等?随机?!我怎么知道使用了哪个端口?

只需查看 docker ps - 有一列:

1
2
3
4
5
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f82dac833ae mariadb:10.3 "docker-entrypoint.s…" 10 days ago Up 9 hours 3306/tcp project_db_1
86f00e7f41a2 phpmyadmin "/docker-entrypoint.…" 10 days ago Up 9 hours 0.0.0.0:8080->80/tcp project_phpmyadmin_1
31ea70729fbf redis:6 "docker-entrypoint.s…" 6 weeks ago Up 9 hours 6379/tcp project_redis_1

PORTS 列中包含你需要的所有信息,甚至更多。它还显示未转发的开放端口。此类端口无法从外部访问(docker 网络除外,但这会改变),但如果你想转发它,你可以获得此信息。

你还可以运行 docker port 来检查给定容器的映射:

1
2
$ docker port project_phpmyadmin_1
80/tcp -> 0.0.0.0:8080

但是它缺少未映射端口的部分,所以我想你不会经常使用该命令 ;)

还有最后一件事我们需要提及,那就是 docker run-P 参数。

1
$ docker run -P ubuntu bash

-P 在主机上的随机端口上开放 Dockerfile 中提到的所有端口。

连接容器

让我们启动一个简单的 Web 服务器:

1
docker run -d --name test_web nginx:alpine

如果我们启动第二个容器,比如说 ubuntu,在其上安装 curl 并尝试访问网页:

1
2
3
4
docker run -t -i --rm ubuntu bash
apt update
apt install curl
curl test_web

这行不通,名称未解析!我们可以使用 docker inspect 并检查 test_web 容器的 IP 是否为 172.17.0.2,然后运行

1
curl 172.17.0.2

而且它可以工作。因此连接性有限,但这是可能的。

如果你熟悉 docker-compose,这可能会令人困惑。docker-compose 中的服务可以使用其名称轻松相互通信!如果你有一个简单的文件,例如:

1
2
3
4
5
6
7
8
9
10
11
12
version: "3.6"
services:
db:
image: mariadb:10.3
environment: ...
phpmyadmin:
image: phpmyadmin
restart: always
ports:
- 8080:80
environment:
- PMA_HOSTS=db

然后 phpmyadmin 显然可以使用其名称 db 连接到 db 服务!
原因很简单,它适用于同一网络内的容器,默认容器除外。

让我们尝试一下!

我们可以通过运行以下命令创建一个新网络:

1
docker network create test

并将现有容器连接到它并运行:

1
2
docker network connect test test_web
docker network connect test NameOfYourBashContainer

我假设测试 bash 容器仍然处于活动状态,你只需在上面的第二行中使用它的名称即可。现在切换回它并运行:

1
curl test_web

可以正常工作!请注意,只要两个容器共享同一网络,就无需开放端口即可从第二个容器访问它。

通过运行以下命令断开其中一个容器与新创建的网络的连接:

1
docker network disconnect test NameOfYourBashContainer

并且名称将不再解析!

还可以在创建容器时将其连接到网络,只需将网络作为输入选项之一传递即可:

1
docker run -t -i --rm --network test ubuntu bash

相关文章: