作为核心网络架构,Libnetwork 还提供了一些重要的网络服务——服务发现。

服务发现(Service Discovery)允许容器和 Swarm 服务通过名称互相定位。唯一的要求就是需要处于同一个网络当中。

其底层实现是利用了 Docker 内置的 DNS 服务器,为每个容器提供 DNS 解析功能。下图展示了容器“c1”通过名称 ping 容器“c2”的过程。Swarm 服务原理相同。

docker compose规定dns docker swarm dns 详解_docker compose规定dns

下面逐步分析整个过程。

1) ping c2 命令调用本地 DNS 解析器,尝试将“c2”解析为具体 IP 地址。每个 Docker 容器都有本地 DNS 解析器。

2) 如果本地解析器在本地缓存中没有找到“c2”对应的 IP 地址,本地解析器会向 Docker DNS 服务器发起一个递归查询。本地服务解析器是预先配置好并知道 Docker DNS 服务器细节的。

3) Docker DNS 服务器记录了全部容器名称和 IP 地址的映射关系,其中容器名称是容器在创建时通过 --name 或者 --net-alias 参数设置的。Docker DNS 服务器知道容器“c2”的 IP 地址。

4) DNS 服务返回“c2”对应的 IP 地址到“c1”本地 DNS 解析器。之所以会这样是因为两个容器位于相同的网络当中,如果所处网络不同则该命令不可行。

5) ping 命令被发往“c2”对应的 IP 地址。

每个启动时使用了 --name 参数的 Swarm 服务或者独立的容器,都会将自己的名称和 IP 地址注册到 Docker DNS 服务。容器和服务副本可以通过 Docker DNS 服务互相发现。

服务发现是受网络限制的,名称解析只对位于同一网络中的容器和服务生效。如果两个容器在不同的网络,那么就不能互相解析。

关于服务发现和名称解析最后要说一点。

用户可以为 Swarm 服务和独立容器进行自定义的 DNS 配置。--dns 参数允许指定自定义的 DNS 服务列表,以防出现内置的 Docker DNS 服务器解析失败的情况。

此外也可以使用 --dns-search 参数指定自定义查询时所使用的域名(例如当查询名称并非完整域名的时候)。

在 Linux 上,上述工作都是通过在容器内部 /etc/resolve.conf 文件内部增加条目来实现的。

Docker服务发布模式

Docker Swarm 支持两种服务发布模式,两种模式均保证服务从集群外可访问。

    Ingress模式(默认)。
    Host模式。
通过 Ingress 模式发布的服务,可以保证从 Swarm 集群内任一节点(即使没有运行服务的副本)都能访问该服务;以 Host 模式发布的服务只能通过运行服务副本的节点来访问。下图展示了两种模式的区别。

docker compose规定dns docker swarm dns 详解_docker_02

Ingress 模式是默认方式,任何时候通过 -p 或者 --publish 发布服务的时候,默认都是 Ingress 模式;如果需要以 Host 模式发布服务,则需要使用 --publish 参数的完整格式,并添加 mode=host。下面一起来看 Host 模式的例子。

$ docker service create -d --name svc1 \
--publish published=5000,target=80,mode=host \
nginx
关于该命令的一些说明。docker service mode 允许使用完整格式语法或者简单格式语法来发布服务。简单格式如 -p 5000:80,前面已经多次出现。不能使用简单格式发布 Host 模式下的服务。

完整格式如 --publish published=5000,target=80,mode=host。该方式采用逗号分隔多个参数,并且逗号前后不允许有空格。具体选项说明如下。

    published=5000 表示服务通过端口 5000 提供外部服务。
    target=80 表示发送到 published 端口 5000 的请求,会映射到服务副本的 80 端口之上。
    mode=host 表示只有外部请求发送到运行了服务副本的节点才可以访问该服务。
通常使用 Ingress 模式。

在底层,Ingress 模式采用名为 Service Mesh 或者 Swarm Mode Service Mesh 的四层路由网络来实现。下图展示了 Ingress 模式下一个外部请求是如何流转,最终访问到服务的。

docker compose规定dns docker swarm dns 详解_Docker_03

上图中最上方命令部署了一个名为“svc1”的 Swarm 服务。该服务连接到了 overnet 网络,并发布到 5000 端口。

按上述方式发布 Swarm 服务(--publish published=5000,target=80)会在 Ingress 网络的 5000 端口进行发布。因为 Swarm 全部节点都接入了 Ingress 网络,所以这个端口被发布到了Swarm范围内。

集群确保到达 Ingress 网络中任意节点的 5000 端口的流量,都会被路由到 80 端口的“svc1”服务。

当前“svc1”服务只部署了一个副本,集群中有一条映射规则:“所有访问 Ingress 网络 5000 端口的流量都需要路由到运行了“svc1”服务副本的节点之上”。

红线展示了访问 Node 的 15000 端口的流量,通过 Ingress 网络,被路由到了 Node2 节点正在运行的服务副本之上。

入站流量可能访问 4 个 Swarm 节点中的任意一个,但是结果都是一样的,了解这一点很重要。这是因为服务通过 Ingress 网络实现了 Swarm 范围内的发布。

此外,还有一点很重要:如果存在多个运行中的副本,流量会平均到每个副本之上,如下图中展示的一样。

docker compose规定dns docker swarm dns 详解_DNS_04

Docker network网络子命令

docker network 命令用于管理网络。可以使用 docker network 的子命令创建,列出,检查,删除,连接和断开网络。

语法格式如下:

docker network COMMAND
docker network connect   将容器连接到网络。
 docker network create     创建新的 Docker 网络。默认情况下,在 Windows 上会采用 NAT 驱动,在 Linux 上会采用Bridge 驱动。可以使用 -d 参数指定驱动(网络类型)。
 docker network disconnect   断开容器的网络。
 docker network inspect    提供 Docker 网络的详细配置信息。
 docker network ls     用于列出运行在本地 Docker 主机上的全部网络。
 docker network prune     删除 Docker 主机上全部未使用的网络。
 docker network rm     删除 Docker 主机上指定网络。