docker dns_Docker网络和DNS:好,坏和难

docker dns

Docker SDN软件定义网络 )已经存在了一段时间。 从版本1.11开始,新功能是增加了DNS循环负载平衡 。 这既是庆祝的原因,又是探索Docker网络DNS的机会。 我们将探索内部和外部网络,了解DNS如何适应情况,讨论可能很合适的用例,并总结其优缺点。

让我们从头开始。 由于我不知道您是Mac,Windows还是Linux用户,因此我们将创建一些运行Ubuntu的VM,并使用它们来模拟Docker Swarm集群。

设置集群

以下示例的唯一要求是VagrantGit 。 我选择Vagrant而不是Docker Machine,这样无论主机OS是Linux,OS X还是Windows,每个人都可以使用相同的命令。 无论您如何设置Docker主机,此处说明的原理都是相同的。

请确保您的笔记本电脑上同时安装了Vagrant和Git。 其他所有内容将自动设置。

我们走吧。 创建和置备VM的命令如下。

git clone https://github.com/vfarcic/docker-flow-proxy.git

cd docker-flow

vagrant plugin install vagrant-cachier

vagrant up swarm-master swarm-node-1 swarm-node-2 proxy

vagrant up命令的执行完成时,我们将获得一个常用的Docker Swarm集群配置。 代理节点托管Consul ,它将充当服务注册表。 目前,缺少代理服务(稍后会详细介绍)。 swarm-master服务器将托管以master模式运行的Swarm 。 最后,两个群集节点( swarm-node-1swarm-node-2 )也正在运行Swarm,但是这次是在节点模式下。 集群节点还托管Registrator ,以确保集群中运行的所有容器都在Consul中注册。 我不会更深入地介绍集群设置,而是专注于Docker网络和DNS功能。

通过Vagrant进行群集集群设置

通过Vagrant进行群集集群设置

让我们输入代理 VM并开始探索不同的网络选项。

vagrant ssh proxy

cd /vagrant/articles/dns

dns目录包含我们在本文中所需的所有代码。

自动创建Docker网络

让我们看看Docker网络的实际应用。 我们将运行一个由两个容器组成的简单服务。 它们被定义为docker-compose-internal.yml文件中的目标appdb 。 其内容如下。

version: '2'

services:
  app:
    image: vfarcic/books-ms
    ports:
      - 8080
    environment:
      - DB_HOST=books-ms-db
    depends_on:
      - db

  db:
    container_name: books-ms-db
    image: mongo
    environment:
      - SERVICE_NAME=books-ms-db

该定义不包含任何与网络相关的内容,因此我们将跳过说明并运行容器。

export DOCKER_HOST=tcp://swarm-master:2375

docker-compose \
    -f docker-compose-internal.yml \
    up -d app

我们指定DOCKER_HOST变量应指向Swarm master并运行Docker Compose目标app 。 由于app目标的定义表明它取决于db ,所以还运行了books-ms-db容器。

up命令的输出如下。

Creating network "dns_default" with the default driver
...
Creating books-ms-db
...
Creating dns_app_1

除非另有说明,否则Docker Compose始终为属于项目的所有容器创建默认网络。 除非使用-p参数指定,否则项目等效于驻留目录Compose的文件(在本例中为dns )。 因此,从输出中可以看到,Docker Compose创建了一个名为dns_default的新网络。

让我们确认刚才运行的容器确实在新创建的网络中。 例如,我们可以尝试从容器dns_app_1内部ping容器books-ms-db

docker exec -it dns_app_1 ping -c 1 books-ms-db

exec命令的输出如下。

PING books-ms-db (10.0.0.2): 56 data bytes
64 bytes from 10.0.0.2: icmp_seq=0 ttl=64 time=0.055 ms
--- books-ms-db ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.055/0.055/0.055/0.000 ms

我们可以看到两个容器都在同一个网络中,并且IP 10.0.0.2被分配给books-ms-db 。 由于这两个容器是使用Swarm部署的,因此它们在不同的服务器中运行。 我们甚至不知道(没有列出过程或查询Consul)每个容器在哪里运行。 关键是,在这种情况下,我们不需要知道容器正在运行的服务器的IP。 只要它属于同一网络,就可以通过其名称访问它。

我们可以反转情况, dns_app_1从容器books-ms-db内部ping容器dns_app_1

docker exec -it books-ms-db ping -c 1 dns_app_1
网络服务1

形成相同服务(在相同docker-compose.yml文件中定义)的所有容器都在同一网络内

让我们看看如果我们指示Swarm部署应用程序目标的其他实例会发生什么。

docker-compose -f docker-compose-internal.yml scale app=2

这次,我们将应用程序目标扩展为两个实例,并且可以对所有容器重复执行ping命令。

docker exec -it dns_app_1 ping -c 1 dns_app_2

docker exec -it dns_app_2 ping -c 1 dns_app_1

docker exec -it dns_app_2 ping -c 1 books-ms-db

如预期的那样,所有三个容器都可以彼此访问。 由于它们属于同一项目(相同的Docker Compose文件),因此Docker将它们全部放在同一网络中,并为每个网络分配了不同的IP。 无论所有容器是同时创建还是以后运行,结果都是相同的。

如果我们运行的新容器这次不属于同一Compose项目,会发生什么情况?

docker run -it --rm alpine ping books-ms-db

run命令的输出如下。

ping: bad address 'books-ms-db'

由于我们运行的容器未在同一Docker Compose项目中定义,因此未将其添加到同一网络中,因此无法访问其他容器。

网络服务2

将同一docker-compose.yml文件中定义的目标之一的任何其他实例添加到同一网络。

这是否意味着容器仅在属于同一个Compose项目时才能相互通信?

在尝试回答该问题之前,让我们销毁容器并重新开始。

docker-compose \
    -f docker-compose-internal.yml \
    down

附带说明一下,当Docker Compose删除网络中的最后一个容器时,它也会同时删除该网络。

将容器添加到外部网络

定义网络的另一种方法是外部的(从Docker Compose的角度来看)。

我们可以使用docker network命令创建一个新网络,然后告诉Compose一些容器应该属于该网络。

docker network create backend

由于DOCKER_HOST变量仍指向Swarm主服务器的IP和端口,因此新创建的网络将覆盖所有群集服务器。

通过执行以下命令,我们可以确认确实创建了backend网络。

docker network ls

network命令的输出应类似于以下内容。

NETWORK ID          NAME                DRIVER
cd2675aa63cf        backend             overlay
2f77d6dd68f7        swarm-node-1/bridge bridge
ce249d5e9344        swarm-node-1/host   host
f65bb111c121        swarm-node-1/none   null
59b0f8b1f82a        swarm-node-2/bridge bridge
021455cd81ae        swarm-node-2/host   host
bd944b062d59        swarm-node-2/none   null

如您所见,除了在Swarm设置过程中创建的网络外, 后端也可用。 我们可以通过Compose或通过使用--net参数执行--net docker run命令来使用它。 docker-compose.yml文件的内容如下。

version: '2'

networks:
  be:
    external:
      name: backend

services:
  app:
    image: vfarcic/books-ms${BOOKS_MS_VERSION}
    ports:
      - 8080
    environment:
      - SERVICE_NAME=books-ms
      - DB_HOST=books-ms-db
    networks:
      default: {}
      be:
        aliases:
          - books-ms
    depends_on:
      - db

  db:
    container_name: books-ms-db
    image: mongo
    environment:
      - SERVICE_NAME=books-ms-db

该Compose文件与我们之前使用的文件几乎相同。 唯一的区别是添加了networks部分。

我们将不讨论整个定义的细节,而是关注networks 。 内部的第一个networks部分(在顶部)称为be 。 它设置为external并且是指网络backend 。 内部名称是我们将在服务内部使用的引用。 如果网络是external网络,则意味着需要在Docker Compose外部手动创建网络。 我们已经通过执行docker network create backend做到了这一点。 最后,网络名称必须与我们通过命令指定的名称相同。

networks部分代表networks的一般定义。 就其本身而言,除非在服务内部定义它,否则它没有任何用途。 因此,我们在app服务中指定了be网络。 稍后我们将探讨aliases

我们将从启动目标app两个实例以及它们所依赖的db开始。

docker-compose up -d app

docker-compose scale app=2

和以前一样,Docker Compose为docker-compose.yml文件中定义的所有容器创建了一个网络。 但是,我们指定了应用程序目标也应该属于后端网络。 结果,我们拥有属于两者的容器dns_app_1dns_app_2 ,而books-ms-db仅位于dns_default网络内部。 这本身并没有提供任何新内容。 无论有没有后端网络,这三个容器都可以彼此“讲话”。

让我们看看如果我们运行一个新的容器会发生什么,但是这次使用--net参数指定它应该属于后端网络。

docker run -it --rm --net backend alpine ping -c 1 dns_app_1

docker run -it --rm --net backend alpine ping -c 1 books-ms-db

这两个命令的输出如下。

PING dns_app_1 (10.0.0.2): 56 data bytes

ping: bad address 'books-ms-db'

由于dns_app_1属于同一网络,因此ping操作成功。 另一方面,第二次ping操作失败,因为books-ms-db容器不属于外部网络后端

网络外部

属于同一外部网络的所有容器都可以互相访问。

我们是否要将请求发送到目标的特定实例(例如dns_app_1 )?

负载均衡请求到多个实例

将请求发送到目标的特定实例违反了扩展的目的。 我们进行扩展是因为我们希望提高性能并在其中一个实例停止工作的情况下提供故障转移。 因此,我们希望在目标的所有实例之间平衡请求。 我们可以使用DNS负载平衡别名轻松地做到这一点。

如果返回到我们先前使用的docker-compose.yml文件,您会注意到在app目标中定义的后端网络具有book-ms别名。 通过向别名发送请求而不是向特定容器名称发送请求,Docker将执行循环负载平衡并将其重定向到实例之一。

作为测试方法,我们将向books-ms别名发送三个ping。

docker run -it --rm --net backend alpine ping -c 1 books-ms

docker run -it --rm --net backend alpine ping -c 1 books-ms

docker run -it --rm --net backend alpine ping -c 1 books-ms

命令的组合输出如下。

PING books-ms (10.0.1.3): 56 data bytes

PING books-ms (10.0.1.3): 56 data bytes

PING books-ms (10.0.1.2): 56 data bytes

而第三个被送到10.0.1.2前两个请求被发送到与IP 10.0.1.3的实例。 Docker别名简化了不同服务之间的通信。 可以将请求转发到哪个实例的选择可以移到发送请求的服务之外。 服务仅需要知道可以通过别名books-ms访问目标服务。 Docker将确保它到达该服务的实例之一。 如果是您的情况,结果可能会有所不同。 别失望 稍后再进行解释。

网络外部DNS

通过别名进行DNS负载平衡

网络用例

在使用Docker和SDN(软件定义网络)时,出现了一些模式,我们可以观察到不同的用例。

Docker Compose自动创建的网络应用于构成同一项目或同一服务的容器之间的内部通信。 这很有用,因为这些容器需要能够彼此“讲话”。 在我们的示例中, 应用程序目标存储并从运行在单独容器中的数据库中检索数据。 该网络之外的任何人都无法访问这些容器。 我们可以称这种类型的内部通信

另一方面, 应用程序目标公开HTTP API。 我们需要其他服务才能调用它。 因此,我们创建了第二个(外部)网络,称为backend 。 由于不应将其他服务访问彼此的数据库,因此将它们从网络中排除。 换句话说,不同服务之间的通信仅可通过其API获得。 我们可以称这种类型的外部通信

允许公众访问服务

那些关注的人会注意到,我们没有提到第三种情况。 我们没有探索从集群外部访问服务的方法。 毕竟,在大多数情况下,我们希望我们的服务是公开的。 我们希望我们的用户能够使用它们。 遗漏的原因在于对于这种类型的访问需要使用不同的工具。 尽管从技术上来说可以使用Docker DNS负载平衡来完成此用例,但该解决方案将不是最优的。

HAProxynginx这样的代理服务是经过负载平衡,反向代理和其他一些事情的经过实践检验的解决方案。 使用我们探索的方法可能无法最好地大规模访问具有潜在巨大负载的扩展服务。 另一方面,容器促进的连续部署需要对这些服务进行不断的重新配置,同时还要进行服务发现,以提供有关集群及其内部运行的所有内容的必要信息。 动态代理重新配置和服务发现不在本文讨论范围之内,并且有许多工具可让您构建自己的解决方案。 我们将仅使用其中之一作为我们要使用代理完成的结果的示例。

由于我们还没有代理,因此我们目前无法从公共网络获得我们尝试的服务。 我们可以通过发送HTTP请求来确认。

curl -I proxy/api/v1/books

curl命令的输出如下。

HTTP/1.0 503 Service Unavailable
Cache-Control: no-cache
Connection: close
Content-Type: text/html

与预期的一样,我们收到503服务不可用响应。

我们可以通过运行代理并将其配置为在服务的两个实例之间执行负载平衡来轻松更改它。 我们将运行docker -compose-proxy.yml文件中定义的vfarcic / docker-flow-proxy容器。 定义如下。

version: '2'

services:
  proxy:
    container_name: docker-flow-proxy
    image: vfarcic/docker-flow-proxy
    environment:
      CONSUL_ADDRESS: 10.100.198.200:8500
    ports:
      - 80:80
      - 443:443
      - 8080:8080

创建VM的过程的一部分是运行代理,因此我们要做的就是重新配置它,以将平衡请求负载到books-ms服务。

curl "proxy:8080/v1/docker-flow-proxy/reconfigure?serviceName=books-ms&servicePath=/api/v1/books"

现在已经配置了代理,我们可以将其用作我们服务的中继。

curl -I proxy/api/v1/books

curl命令的输出如下。

HTTP/1.1 200 OK
Server: spray-can/1.3.1
Date: Sat, 23 Apr 2016 17:47:20 GMT
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=UTF-8
Content-Length: 2

这次,响应为200 OK ,表示确实可以通过代理访问该服务。

通过将代理与Docker网络和DNS相结合的结果,我们解决了对服务的公共访问,负载平衡以及容器之间的内部通信。

代理

代理结合Docker网络和DSN

如果您对我们使用的代理的更多详细信息感兴趣,请阅读Docker Flow:Proxy –按需HAProxy服务发现和重新配置一文,或直接跳至Docker Flow:Proxy项目。

黄金三镖客

让我们Swift评估本文中探讨的实践和技术。

好(立即采用)

Docker网络存在多个版本,并且很稳定。 没有集群,操作集群内的容器会非常痛苦且复杂。 链接不能跨越多个容器,而不会涉及变通办法,技巧和“巫术”。 这是Swarm的一个重要里程碑,在许多情况下,它也是在集群中运行容器的最佳解决方案。

DNS轮询很容易定义和使用。 对此功能大胆支持Docker。 当我们需要允许内部 好丑 不同的容器。 没有它,只有当目标服务只有一个实例时,Docker网络才真正有用。 借助DNS,我们可以开始考虑大规模使用Docker SDN。

坏消息(可能有用,但仍处于起步阶段)

虽然Engine 1.11中的DNS解析器将对记录进行随机化(即在每次请求时以不同的顺序返回记录),但大多数DNS解析器将对记录进行排序。 结果,轮询将无法真正按预期工作。 当我们通过DNS对目标目标应用程序进行三个ping操作时,您看到了该示例。 即使没有其他人正在访问该服务,前两个请求也转到第一个实例,而第三个请求转到第二个实例(在您的情况下,顺序可能有所不同)。 真正的轮询将再次向第一个实例发出第一个请求,向第二个实例发出第二个请求,再向第一个实例发出第三个请求。 问题不在于Docker的实现,而在于DNS本身。 尽管在许多情况下,这种偏差不应引起问题,但仍然可以使用更好的解决方案。 从好的方面来说,这一新增功能是一个非常重要的里程碑,我们还没有看到下一版本将带来的改进。

丑陋(请勿使用)

Docker的DNS与别名结合使用有很多用途,但是面向大流量的面向公众的负载平衡并不是其中之一。 不要试图用它替换您的代理。 HAProxy和nginx(仅举几例)经过了实战测试,并证明在几乎所有负载下都能正常工作。 通过运行状况检查,反向代理,URL重写和许多其他功能,它们不仅仅具有简单的循环负载均衡器。 使用代理时的挑战是基于服务发现的动态重新配置,但这既不会降低其价值,也不会证明切换至Docker DNS的合理性。 另一方面,代理不会降低我们在1.11版中获得的价值。 它是工具带中的又一个工具,我们的工作是知道何时使用一个工具。 请阅读Docker Flow:代理-按需HAProxy服务发现和重新配置一文,了解更多信息。 即使您不选择使用Docker Flow:Proxy ,它也可以洞悉我们对充满容器的集群中的代理的期望。

DevOps 2.0工具包

如果您喜欢本文,则可能对DevOps 2.0工具包:使用容器化微服务自动化持续部署管道一书感兴趣。 在许多其他主题中,它更详细地探讨了Docker集群和网络。

本书介绍了不同的技术,这些技术可以帮助我们更好,更高效地构建软件,并将微服务包装为不可变的容器 ,并进行测试连续部署到由配置管理工具自动 配置的服务器上。 它是关于零停机时间回滚能力的快速,可靠和连续的部署。 它涉及到可扩展到任意数量的服务器,能够从硬件和软件故障中恢复的自我修复系统的设计以及有关群集的集中式日志记录和监视

换句话说,这本书使用一些最新和最好的实践和工具来涵盖整个微服务开发和部署生命周期 。 我们将使用Docker,Ansible,Ubuntu,Docker Swarm和Docker Compose,Consul,etcd,Registrator,confd,Jenkins,nginx等。 我们将介绍许多实践,甚至更多的工具。

该书可从Amazon( Amazon.com和其他全球站点)和LeanPub获得

翻译自: https://www.javacodegeeks.com/2016/04/docker-networking-dns-good-bad-ugly.html

docker dns

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值