设为首页 收藏本站
查看: 1766|回复: 0

[经验分享] 使用 Etcd 和 Haproxy 做 Docker 服务发现

[复制链接]
累计签到:24 天
连续签到:1 天
发表于 2015-11-20 12:37:11 | 显示全部楼层 |阅读模式
使用 Etcd 和 Haproxy 做 Docker 服务发现
  标签(空格分隔): Etcd Haproxy Docker 服务发现 architecture discovery docker-gen golang service


  本文作者是 jwilder,本文的原文是 Docker Service Discovery Using Etcd and Haproxy

  在前一篇文章中,我们展示了一种为 Docker 容器在同一台主机上创建一个自动化 Nginx 反向代理的方式。那个设置对于前端 web app 来说工作的很好,但是对于后端服务来说它不是一个好的点子,因为通常它们跨越多个主机。
  这篇文章描述了一个为后端服务的 Docker 容器提供服务发现的解决方案。
  我们将构建的架构体系是模仿 SmartStack,但是使用 etcd 代替 Zookeeper,和两个 docker 容器运行 docker-gen 和 haproxy 代替 nerve 和 synapse。

它怎样工作的
DSC0000.png
  类似于 SmartStack,我们的组件服务作为一个注册(etcd),一个注册伙伴进程(docker-register),发现伙伴进程(docker-discover),一些后端服务(whoami)以及最后一个消费者(ubuntu/curl)。
  注册和发现组件作为设备与应用程序容器工作,因此在后端或消费者容器的注册或发现代码不是被嵌入的。它们仅仅监听端口或连接其他本地端口。

服务注册 - Etcd
  在任何事情被注册之前,我们需要一些地方跟踪注册条目(比如,服务的 IP 和端口)。我们使用 etcd,因为它由服务注册的简单程序模型和支持键的 TTLs 以及目录。
  通常,你将运行 3到5个 etcd 节点,但是我们仅仅使用一个来保持事情简化。
  没有理由为什么我们不能使用 Consul 或任何其他存储选项支持 TTL 过期。
  开始 etcd:

docker run -d --name etcd -p 4001:4001 -p 7001:7001 coreos/etcd

服务注册 - docker-register
  注册服务容器被 jwilder/docker-register 容器处理。这个容器注册其他运行在同一台主机上的容器到 etcd 中。我们想注册的容器必须暴露一个端口。容器在不同的主机上运行相同的镜像是在 etcd 中被分组并将构成一个负载均衡集群。容器怎样分组是有点乱的,为这个演练我已经选择了容器镜像名字。在一个真实的部署中,你可能想通过环境变量,服务版本或其他的元数据分组。
  (当前的实现仅仅支持每个容器一个端口并假设它当前是 TCP,没有理由为什么不能支持多个端口和类型以及不同的分组属性)
  docker-register 使用 docker-gen连同一个 Python 脚本作为一个模板。当运行的时候,动态的生成一个脚本,将在 /backends 目录注册每个容器的 IP 和端口。
  docker-gen 关注监控 docker events和调用在一个间隔调用生成脚本来确保 TTLs 始终在最近的日期,如果 docker-register 停止了,注册过期。
  为了启动 docker-register,我们需要传递主机的外部 IP,其他的主机能访问它的容器以及你的 etcd 主机的地址。 为了调用它的 API,docker-gen 要求访问 docker daemon,因此我们也绑定挂载 docker 的 unix socket 到容器中。

HOST_IP=$(hostname --all-ip-addresses | awk '{print $1}')
ETCD_HOST=w.x.y.z:4001
docker run --name docker-register -d -e HOST_IP=$HOST_IP -e ETCD_HOST=$ETCD_HOST -v /var/run/docker.sock:/var/run/docker.sock -t jwilder/docker-register

服务发现 - docker-discover
  服务发现被 jwilder/docker-discover 容器处理。 docker-discover 周期性的投票 etcd 并通过监听每个服务类型来生成一个 haproxy 配置文件。
  比如,容器运行 jwilder/whoami 被注册在 /backends/whoami/<id>以及被暴露在主机上的端口是 8000。
  其他的容器需要调用 jwilder/whoami 服务,可以发送请求到 docker bridge IP:8000 或主机 IP:8000。
  如果任何的后端服务宕了,haproxy 健康检查从池子中移除它并将在一台健康的主机上尝试请求。这确保后端服务可以随着需求被启动和停止,以及处理注册信息的不一致同时确保最小化的客户端影响。
  最后,stats 可以通过在 docker-discover 容器上访问端口 1936 来查看。
  运行 docker-discover:

ETCD_HOST=w.x.y.z:4001
docker run -d --net host --name docker-discover -e ETCD_HOST=$ETCD_HOST -p 127.0.0.1:1936:1936 -t jwilder/docker-discover

  我们正在使用 --net host 以至于容器使用主机网络栈。当这个容器绑定 8000 端口,它实际是绑定在主机的网络上。这个简化了代理的设置。

AWS Demo
  我们将在 4 台 AWS 主机上运行整套服务:一台 etcd 主机, 一台 client 主机 和 两台后端主机。后端服务 是一个简单的返回主机名的 golang HTTP 服务。

Etcd 主机
  首先,我们启动 etcd 注册:

$ hostname --all-ip-addresses | awk '{print $1}'
10.170.71.226
$ docker run -d --name etcd -p 4001:4001 -p 7001:7001 coreos/etcd

  我们的 etcd 地址是 10.170.71.226。我们将在其他主机上使用它。如果我们正在运行的是一个在线环境,我们可以分配一个 EIP 和 DNS 地址给它使得它更容易配置。

后端主机
  下一步,我们在每台主机上启动这个服务和 docker-register。该服务被配置成监听容器中的 8000 端口并且我们让 docker 把它发布在一台主机上的随机端口。
  后端主机 1:

$ docker run -d -p 8000:8000 --name whoami -t jwilder/whoami
736ab83847bb12dddd8b09969433f3a02d64d5b0be48f7a5c59a594e3a6a3541
$ docker run --name docker-register -d -e HOST_IP=$(hostname --all-ip-addresses | awk '{print $1}') -e ETCD_HOST=10.170.71.226:4001 -v /var/run/docker.sock:/var/run/docker.sock -t jwilder/docker-register
77a49f732797333ca0c7695c6b590a64a7d75c14b5ffa0f89f8e0e21ae47ae3e
$ docker ps
CONTAINER ID        IMAGE                            COMMAND                CREATED             STATUS              PORTS                     NAMES
736ab83847bb        jwilder/whoami:latest            /app/http              48 seconds ago      Up 47 seconds       0.0.0.0:49153->8000/tcp   whoami
77a49f732797        jwilder/docker-register:latest   &quot;/bin/sh -c 'docker-   28 minutes ago      Up 28 minutes                                 docker-register

  后端主机 2:

$ docker run -d -p 8000:8000 --name whoami -t jwilder/whoami
4eb0498e52076275ee0702d80c0d8297813e89d492cdecbd6df9b263a3df1c28
$ docker run --name docker-register -d -e HOST_IP=$(hostname --all-ip-addresses | awk '{print $1}') -e ETCD_HOST=10.170.71.226:4001 -v /var/run/docker.sock:/var/run/docker.sock -t jwilder/docker-register
832e77c83591cb33bba53859153eb91d897f5a278a74d4ec1f66bc9b97deb221
$ docker ps
CONTAINER ID        IMAGE                            COMMAND                CREATED             STATUS              PORTS                     NAMES
4eb0498e5207        jwilder/whoami:latest            /app/http              59 seconds ago      Up 58 seconds       0.0.0.0:49154->8000/tcp   whoami
832e77c83591        jwilder/docker-register:latest   &quot;/bin/sh -c 'docker-   34 minutes ago      Up 34 minutes                                 docker-register

客户端主机
  在客户端主机,我们需要启动 docker-discover 和一个客户端服务。对于这个客户端容器,我使用 Ubuntu Trusty 并将做一些
curl 请求。
  首先,启动 docker-discover:

$ docker run -d --net host --name docker-discover -e ETCD_HOST=10.170.71.226:4001 -p 127.0.0.1:1936:1936 -t jwilder/docker-discover

  然后,启动一个简单的客户端容器并传给它 HOST_IP。我们正在使用 eth0 地址,但也可以使用 docker0 IP。我们正以一个环境变量传给它因为它是被配置的在两个部署之间变化的。

$ docker run -e HOST_IP=$(hostname --all-ip-addresses | awk '{print $1}') -i -t ubuntu:14.04 /bin/bash
$ root@2af5f52de069:/# apt-get update && apt-get -y install curl

  这时,构造一些请求给 whoami 服务端口 8000 来看他们的负载。

$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm 4eb0498e5207
$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm 736ab83847bb
$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm 4eb0498e5207
$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm 736ab83847bb

  我们可以在后端启动一些实例:

$ docker run -d -p :8000 --name whoami-2 -t jwilder/whoami
$ docker run -d -p :8000 --name whoami-3 -t jwilder/whoami
$ docker ps
CONTAINER ID        IMAGE                            COMMAND                CREATED             STATUS              PORTS                     NAMES
5d5c12c96192        jwilder/whoami:latest            /app/http              3 seconds ago       Up 1 seconds        0.0.0.0:49156->8000/tcp   whoami-2
bb2a408b8ec5        jwilder/whoami:latest            /app/http              21 seconds ago      Up 20 seconds       0.0.0.0:49155->8000/tcp   whoami-3
4eb0498e5207        jwilder/whoami:latest            /app/http              2 minutes ago       Up 2 minutes        0.0.0.0:49154->8000/tcp   whoami
832e77c83591        jwilder/docker-register:latest   &quot;/bin/sh -c 'docker-   36 minutes ago      Up 36 minutes                                 docker-register

  然后再次在客户端主机上构造一些请求:

$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm 736ab83847bb
$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm 4eb0498e5207
$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm bb2a408b8ec5
$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm 5d5c12c96192
$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm 736ab83847bb

  最后,我们关闭一些容器,路由将被更新。这个杀死在后端 2 的任何东西。

$ docker kill 5d5c12c96192 bb2a408b8ec5 4eb0498e5207
$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm 736ab83847bb
$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm 67c3cccbb8ba
$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm 736ab83847bb
$ root@2af5f52de069:/# curl $HOST_IP:8000
I'm 67c3cccbb8ba

  如果你想看 haproxy 是怎样负载流量的或监控错误,我们可以在 web 浏览器访问客户端主机的 1936 端口。

总结
  虽然有不同的方式来实现服务发现,SmartStack 的伙伴注册行为和代理保持应用程序代码简单以及非常容易的融合进一个分布式环境,真的适合 Docker 容器。
  同样地,Docker 的事件和容器 APIs 减轻了服务注册和使用注册服务发现(比如 etcd)的困难。
  docker-register 和 docker-discover 的代码在 github 上。虽然两个都是有用的,但是有很多地方需要提升。请随时提交或提出改进意见。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-141498-1-1.html 上篇帖子: 自动化运维-自动化扩容介绍加etcd部署 下篇帖子: Docker服务发现(二) --使用 Etcd 和 Haproxy
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表