Docker 网络:概述。





5.00/5 (5投票s)
本文为您入门 Docker 网络打下基础。让我们让容器之间能够通信。
Docker 自诞生以来就备受关注,几乎万物皆可 Docker 化已成为热门话题。作为一种热门技术,它正受到越来越多的关注,无论是开发者还是企业。随着 IT 世界转向 **虚拟化**,网络范式也从配置物理路由器、交换机、LAN/WAN 转向了虚拟化平台中的网络组件,即虚拟机、云和其他。现在,当我们谈论由 **容器** 组成的奇妙世界时,人们需要具备强大的网络技能才能正确配置容器架构。如果您希望部署的容器能够根据微服务的需求和喜好进行扩展,那么您就需要将网络配置得恰到好处。这就是 Docker 网络发挥作用的地方;平衡应用程序需求和网络环境。这就是我在这里要做的,为您提供 Docker 网络概述。
我们将从小处着手,谈谈 Docker 网络的基础知识,然后逐步深入,使用 Docker 网络提供的更近期和更高级的选项来让容器相互通信。请注意,本文并非面向完全的 Docker 初学者,而是假设您具备 Docker 和容器的基本知识。我**不会**谈论什么是 Docker 或容器,我的重点将放在通过提供网络概述来使 Docker 学习曲线更平滑,所以如果我有些许的急转弯,请不要介意。
一些背景信息
容器为您的所有主机之间的网络工作方式带来了全新的理念,因为它将包含运行应用程序所需的一切:代码、运行时、系统工具、系统库、设置以及一切。
这应该能清楚地表明,容器将应用程序与系统的其余部分隔离开来,以确保环境的稳定性。这正是 Docker(别忘了 Docker 是最受欢迎的容器化工具)的全部意义所在,对吧?将应用程序与您的基础设施分离,以确保快速开发、交付和运行应用程序。到目前为止一切都很好,但每台主机可能有成百上千个容器。此外,我们的微服务可以分布在多台主机上。那么,我们如何让容器与外部世界通信呢?例如,我们需要以某种方式访问它们以使用它们提供的服务。另外,我们如何让容器与主机或其他容器通信呢?为此,我们需要容器之间某种形式的连接,而这正是 Docker 网络发挥作用的地方。
坦白地说,Docker 网络在早期并不值得称道。它很复杂,而且不易扩展。直到 2015 年之后;当 Docker 掌握了 Socket Plane;Docker 网络才开始闪耀。从那时起,开发社区做出了许多有趣的贡献,包括 Pipework、Weave、Clocker 和 Kubernetes。Docker 公司也通过建立一个名为 **libnetwork** 的标准化网络项目来发挥作用,该项目实现了 **容器网络模型**(**CNM**)。本文将重点关注相同的容器网络模型。
容器网络模型
容器网络模型可以被认为是 Docker 网络的核心。它旨在将网络作为与容器运行时分离的库,而不是通过 **驱动程序**(bridge、overlay、weave 等)作为插件来实现。
这就是 CNM 的全部哲学。您可以认为它充当了一个抽象层,用于分散通用网络的复杂性,并支持多种网络驱动程序。该模型有三个主要组成部分:
沙箱 (Sandbox):包含容器网络堆栈的配置
端点 (Endpoint):将沙箱连接到网络
网络 (Network):一组可以直接通信的端点
这是该模型的一个图示。
该项目托管在 Github 上。如果您想了解更多关于 CNM 模型的信息,我鼓励您继续阅读并仔细研究。
我也听过 CNI……?
是的!容器网络接口 (CNI) 是另一个容器网络标准,由 CoreOS 发起,被 Cloud Foundry、Kubernetes 等使用,但这超出了本文的范围。这就是为什么我没有触及这个领域。我可能会在接下来的文章中讨论它,但目前请谅解。欢迎您自行搜索和学习。
Libnetwork
libnetwork
实现的正是我们刚才讨论的 CNM 模型。Docker 的推出遵循提供卓越用户体验和跨基础设施的无缝应用程序可移植性的理念。网络也遵循相同的理念。**可移植性** 和 **可扩展性** 是 libnetwork
项目背后的两个主要因素。该项目的长期目标,如 官方 所述,是遵循 Docker 和 Linux 的理念,提供小型、高度模块化且可组合的工具,这些工具能够独立良好地工作,旨在满足容器中对网络的可组合性需求。Libnetwork
不仅仅是一个驱动程序接口,它还有更多功能。它的一些主要功能包括:
- 内置 IP 地址管理
- 多主机网络
- 服务发现和负载均衡
- 插件以扩展生态系统
到目前为止,这些内容应该都能说得通了。话虽如此,我觉得聊得够多了,是时候动手实践一下了。
网络模式的一些乐趣
我假设您已经在机器上安装了 Docker。如果没有,请按照 此处 的文档进行安装。我在 Linux (Ubuntu 18.04 LTS) 上工作,所以我现在将展示的一切在相同环境下都能很好地工作,而且更有趣的是;由于我们谈论的是 Docker;对于 Mac、Windows 或您可能正在使用的任何其他平台,事情应该也不会有太大差别。您可以通过简单地检查版本来确保安装。
$ docker version
您应该会看到类似以下的输出:
root@mehreen-Inspiron-3542:/home/mehreen# docker version
Client:
Version: 18.06.1-ce
API version: 1.38
Go version: go1.10.3
Git commit: e68fc7a
Built: Tue Aug 21 17:24:51 2018
OS/Arch: linux/amd64
Experimental: false
Server:
Engine:
Version: 18.06.1-ce
API version: 1.38 (minimum version 1.12)
Go version: go1.10.3
Git commit: e68fc7a
Built: Tue Aug 21 17:23:15 2018
OS/Arch: linux/amd64
Experimental: false
现在我们可以开始工作了。您可以使用以下命令查看网络可用的命令:
$ docker network
这将产生以下输出:
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
Run 'docker network COMMAND --help' for more information on a command.
让我们看看还有什么等待着我们。
默认网络模式
默认情况下,有一些网络模式是激活的。它们也可以称为单主机 Docker 网络模式。要查看 Docker 网络,请运行:
$ docker network ls
上述命令将输出以下三个选项:
相当直观。Bridge、Host 和 None 网络是为我们默认创建的,它们使用 bridge、host 和 null 驱动程序。需要注意的一点是,它显示作用域为 **local**,这意味着这些网络仅适用于此主机。但这些网络究竟有何不同?让我们看看。
Bridge 网络模式
Docker **守护进程** 创建一个“docker0
”虚拟以太网桥,该桥在连接到它的所有接口之间转发数据包。让我们使用 inspect 命令并指定网络的名称或 ID 来更深入地检查此网络:
$ docker network inspect bridge
它将输出网络的全部规格和配置。
root@mehreen-Inspiron-3542:/home/mehreen# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "f47f4e8e34ebe75035115b88e301ac9548eb99e429cb8d9d9b387dec07a2db5f",
"Created": "2018-10-13T14:34:39.071898384+05:00",
"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": {},
"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": {}
}
]
如上所示,docker0
网络由 bridge
表示。此外,子网和网关是为它自动创建的。通过简单的 `docker run` 命令,容器可以自动添加到此网络;如果已有容器连接到该网络,则 inspect 命令会显示它们。最后但并非最不重要的是,容器之间的通信默认是启用的。我们将在本文稍后利用所有这些。
Host 网络模式
让我们检查一下这种网络模式,看看屏幕上会显示什么。
root@mehreen-Inspiron-3542:/home/mehreen# docker network inspect host
[
{
"Name": "host",
"Id": "fbfb142290eeaf9f696467932b0f5d4e350dd3fd5fba22ad8dd495fde42bd9ea",
"Created": "2018-10-13T14:11:27.536955704+05:00",
"Scope": "local",
"Driver": "host",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": []
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
这使得容器可以共享主机的网络命名空间,这意味着它直接暴露给外部世界。因此,没有自动端口分配,也没有路由,但您必须使用端口映射来访问容器内的服务,因为容器内的配置与外部相同。
None 网络模式
以下是检查此网络的结果:
root@mehreen-Inspiron-3542:/home/mehreen# docker network inspect none
[
{
"Name": "none",
"Id": "75201eb0dee7bdac624d20c4aab536b73f49c5a6b9230a97d3f5f5424622e4c4",
"Created": "2018-10-13T14:11:27.390186279+05:00",
"Scope": "local",
"Driver": "null",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": []
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
等等,这里和我们上次检查的有什么不同吗?这是否意味着两者相同?不,一点也不。None 网络模式提供了一个特定于容器的网络堆栈,它没有外部网络接口。它只有一个本地回环接口。
但**能**通信的容器在哪里?
是的!我们看到了网络,但是我们还没有将任何容器添加到网络中,也没有它们之间的任何明显通信。现在是时候给我们的生活增添一些甜头了。让我们创建自己的网络,看看能否让我们的容器相互通信。
我们将使用 bridge 驱动程序创建一个单主机 bridge 网络。因为它简单易懂、易于使用和排除故障,所以它非常适合初学者。
通过执行以下命令创建 bridge 网络:
$ docker network create -d bridge testbridge
这将创建我们命名为 testbridge
的网络,使用 bridge
驱动程序。如果上面的命令返回一长串字符,则表示执行成功。让我们快速检查网络列表,看看我们的网络是否出现在那里。
我们做到了。现在,如果您检查这个网络,它会与我们之前检查的 bridge 网络一样。让我们将一些容器连接到我们的网络。
$ docker run -dt --name cont_test1 --network testbridge alpine
我们在之前创建的 testbridge
网络上创建了一个名为 cont1
的容器。我使用了 alpine
镜像来创建容器。(使用 alpine 镜像没有特别原因,只是因为它很轻量级。您可以使用其他任何镜像,如 ubuntu
等。命令都会正常工作。)响应再次应该是一长串字符。让我们再创建一个类似的容器。
$ docker run -dt --name cont_test2 --network testbridge alpine
现在我们有了两个容器在同一个 bridge 网络上。您想检查一下网络吗?我检查了,以下是我发现的内容。
----------------------------------------------------------------------
"Containers": {
"88ae819d1549527e36b62f50f563c124aa3bc23ae141964201f59601203848f9": {
"Name": "cont_test2",
"EndpointID": "1bd9a68af20b3abf44f94dbd98a2c846bbeb02f016359209a373bf0c54501d69",
"MacAddress": "02:42:ac:13:00:05",
"IPv4Address": "172.19.0.5/16",
"IPv6Address": ""
},
"a1a4f170a616a8c1fa3cac5f746f26470c778f807c30afe4a8e7d44ee702d7ca": {
"Name": "cont_test1",
"EndpointID": "7bb7dbc24b89291b41b31e7d5ffbf0e5c46358122744ad16043f99593da1d41e",
"MacAddress": "02:42:ac:13:00:04",
"IPv4Address": "172.19.0.4/16",
"IPv6Address": ""
},
-------------------------------------------------------------------------
我们两个容器现在都已添加到网络中。但是它们能通信吗?让我们进入其中一个容器,尝试 ping 另一个容器,看看是否有效。
$ docker exec -it cont_test1 sh
我们现在在第一个容器中。让我们通过指定名称或 IP 来 ping 另一个容器。
root@mehreen-Inspiron-3542:/home/mehreen# docker exec -it cont_test1 sh
/ # ping cont_test2
搞定!我们的容器正在相互通信。但是,如果我们尝试 ping Google 呢?
它奏效了!
下一步是什么?
我们的容器可以相互通信,也可以与外部世界通信。您还可以使用其他命令,如 docker stop
和 docker rm
来停止和删除容器。 正如我多次提到的,我们讨论的是单主机网络。如果我们尝试与另一台主机上的容器通信,那将不起作用。为此,需要多主机网络,这也会引入 **swarm** 的概念。看来还有很多东西需要学习。我可能会在下一篇文章中介绍。在那之前,您可以随意探索。