在这篇文章中,咱们将讨论如何用Rancher实现consul的服务发现。java
若是你尚未准备好,推荐你阅读本系列中先前的文章: 第一篇:CI /CD和Docker入门 第二篇:使部署逻辑向使用Docker Compose更进一步 第三篇:借力Rancher完成容器编排nginx
在这构建部署流水线系列的最后一篇文章中,咱们将探讨在转换到Rancher进行集群调度时面临的一些挑战。在以前的文章中,咱们经过使用Rancher执行调度,让运维人员无须再负责选择每一次容器运行的位置。要使用这个新方案,咱们必须让环境的其余部分知道调度程序放置这些服务的位置,以及如何访问它们。咱们还将讨论如何使用标签来操做调度程序,以调整容器放置位置,并避免端口绑定冲突。最后,咱们将经过利用Rancher的回滚功能优化咱们的升级过程。docker
在引入Rancher以前,咱们的环境是一个至关静态的环境。咱们老是将容器部署到相同的主机上,而部署到不一样的主机则意味着咱们须要更新一些配置文件以反映新位置。例如,若是咱们要添加'java-service-1'应用程序的一个附加实例,咱们还须要更新load balancer以指向附加实例的IP。使用调度器让咱们没法预测容器部署的位置,而且咱们须要动态配置环境,使其能自动适应变化。为此,咱们须要使用服务注册和服务发现。编程
服务注册表为咱们提供了应用程序在环境中的位置的单一来源。和硬编码服务位置不一样,咱们的应用程序能够经过API查询服务注册表,并在咱们的环境发生变化时自动从新配置。Rancher使用Rancher的DNS和元数据服务提供了开箱即用的服务发现。然而,混合使用Docker和非Docker应用程序时,咱们不能彻底依赖Rancher来处理服务发现。咱们须要一个独立的工具来跟踪咱们全部服务的位置,consul就符合这个要求。后端
咱们不会详细说明如何在您的环境中设置Consul,可是,咱们将简要描述咱们在ABC公司使用Consul的方式。在每一个环境中,咱们都有一个部署为容器的Consul集群。咱们在环境中的每一个主机上都部署一个Consul代理,若是主机正在运行Docker,咱们还会部署一个注册器容器。注册器监视每一个守护进程的Docker事件API,并在生命周期事件期间自动更新Consul。例如,在新容器被部署后,注册器会自动在Consul中注册该服务。当容器被删除时,注册器撤销它的注册。api
在Consul中注册全部服务后,咱们能够在负载均衡器中运行consul-template,根据Consul中存储的服务数据动态填充上游列表。对于咱们的NGINX负载均衡器,咱们能够建立一个模板来填充’java-service-1’应用程序的后端:微信
# upstreams.conf upstream java-service-1 { {{range _, $element := service "java-service-1"}} server {{.Address}}:{{.Port}}; {{else}} server 127.0.0.1:65535; # force a 502{{end}} }
此模板在Consul中查找注册为“java-service-1”的服务的列表。而后它将循环该列表,添加具备该特定应用程序实例的IP地址和端口的服务线。若是在Consul中没有注册任何“java-service-1”应用程序,咱们默认抛出502以免NGINX中的错误。负载均衡
咱们能够在守护进程模式下运行consul-template,使其监控Consul的更改,在发生更改时从新渲染模板,而后从新加载NGINX以应用新配置。less
TEMPLATE_FILE=/etc/nginx/upstreams.conf.tmpl RELOAD_CMD=/usr/sbin/nginx -s reload consul-template -consul consul.stage.abc.net:8500 \ -template "${TEMPLATE_FILE}:${TEMPLATE_FILE//.tmpl/}:${RELOAD_CMD}"
经过使用咱们的负载均衡器设置来动态地改变其他的环境变化,咱们能够彻底依赖Rancher调度器来作出咱们的服务应该在哪里运行的复杂的决定。可是,咱们的“java-service-1”应用程序在Docker主机上绑定TCP端口8080,若是在同一主机上调度了多个应用程序容器,则会致使端口绑定冲突并最终失败。为了不这种状况,咱们能够经过调度规则来操做调度器。运维
经过在docker-compose.yml文件中使用容器标签来提出条件,是Rancher给咱们的一种操做调度器的方法。条件能够包括亲和规则、否认、至“软”强制(意味着尽量地避免)。在咱们使用'java-service-1'应用程序的状况下,咱们知道在给定时间只有一个容器能够在主机上运行,所以咱们能够基于容器名称设置反关联性规则。这将使调度程序查找一个未运行名称为“java-service-1”的容器的Docker主机。咱们的docker-compose.yml文件看起来像下面这样:
java-service-1: image: registry.abc.net/java-service-1:${VERSION} container_name: java-service-1 ports: - 8080:8080 labels: io.rancher.scheduler.affinity:container_label_ne: io.rancher.stack_service.name=java-service-1
注意“标签”键的引入。全部调度规则都做为标签被添加。标签能够被添加到Docker主机和容器。当咱们在Rancher注册咱们的主机时,咱们能够将它们与标签关联,之后就能够切断调度部署。例如,若是咱们有一组使用SSD驱动器进行存储优化的Docker主机,咱们能够添加主机标签storage=ssd。
须要利用优化存储主机的容器能够添加标签来强制调度程序仅在匹配的主机上部署它们。咱们将更新咱们的“java-service-1”应用程序,以便只部署在存储优化的主机上:
java-service-1: image: registry.abc.net/java-service-1:${VERSION} container_name: java-service-1 ports: - 8080:8080 labels: io.rancher.scheduler.affinity:container_label_ne: io.rancher.stack_service.name=java-service-1 io.rancher.scheduler.affinity:host_label: storage=ssd
经过使用标签,咱们能够根据所需的容量,而不是个别主机运行特定的容器集,来精细地调整咱们的应用程序部署。切换到Rancher进行集群调度,即便您仍然有必须在特定主机上运行的应用程序。
最后,咱们能够利用Rancher的回滚功能优化咱们的服务升级。在咱们的部署工做流中,经过调用rancher-compose来指示Rancher在该服务堆栈上执行升级以部署服务。升级过程大体以下:
当给定服务的部署很是少时,此工做流就行了。可是,当某个服务处于“升级”状态(在部署者选择“完成升级”以前)时,在执行“完成升级”或是“回滚”操做以前,你都不能对它进行任何新的升级”。rancher-compose实用程序让咱们能够选择以编程方式选择要执行的操做,以部署程序者的身份执行操做。例如,若是您对服务进行自动测试,则能够在rancher-compose升级返回后调用此类测试。根据这些测试的状态,rancher-compose能够被再次调用,此次咱们告诉堆栈“完成升级”或“回滚”。咱们部署Jenkins做业的一个原始示例可能以下:
# for the full job, see part 3 of this series /usr/local/bin/rancher-compose --verbose \ -f ${docker_dir}/docker-compose.yml \ -r ${docker_dir}/rancher-compose.yml \ up -d --upgrade JAVA_SERVICE_1_URL=http://java-service-1.stage.abc.net:8080/api/v1/status if curl -s ${JAVA_SERVICE_1_URL} | grep -q "OK"; then # looks good, confirm or "finish" the upgrade /usr/local/bin/rancher-compose --verbose \ -f ${docker_dir}/docker-compose.yml \ -r ${docker_dir}/rancher-compose.yml \ up --confirm-upgrade else # looks like there's an error, rollback the containers # to the previously deployed version /usr/local/bin/rancher-compose --verbose \ -f ${docker_dir}/docker-compose.yml \ -r ${docker_dir}/rancher-compose.yml \ up --rollback fi
这个逻辑将调用咱们的应用程序端点来执行简单的状态检查。若是输出显示的是‘OK’,那么咱们完成升级,不然咱们须要回滚到之前部署的版本。若是您没有自动测试,另外一个选择是简单地老是完成或“确认”升级。
# for the full job, see part 3 of this series /usr/local/bin/rancher-compose --verbose \ -f ${docker_dir}/docker-compose.yml \ -r ${docker_dir}/rancher-compose.yml \ up -d --upgrade --confirm-upgrade
若是不久之后,您肯定须要回滚,就使用相同的部署做业简单地从新部署之前的版本。这确实不像Rancher的升级和回滚功能那么友好,但它经过使堆栈不处于“升级”的状态来解锁未来的升级。
当服务在Rancher中回滚时,容器将被从新部署到之前的版本。当使用通用标记如“latest”或“master”部署服务时,可能会出现意外的后果。例如,让咱们假设'java-service-1'应用程序之前被部署了标签'latest'。对图像进行更改,推送到注册表,Docker标签“latest”被更新为指向此新映像咱们使用标签“latest”继续升级,在测试后决定应用程序须要回滚。使用Rancher滚动堆栈仍然会从新部署最新的映像,由于标签“latest”还没有被更新为指向上一个映像。回滚能够在纯技术术语中实现,可是部署最近的工做副本的预期效果彻底没法实现。在ABC公司,咱们经过始终使用与应用程序版本相关的特定标记来避免这种状况。所以,不要使用标记latest”部署咱们的“java-service-1”应用程序,咱们可使用版本标签“1.0.1-22-7e56158”。这保证回滚将始终指向咱们的应用程序在环境中的最新工做部署。
咱们但愿咱们分享的经验对大家有所帮助。这有助于咱们有条不紊地采用Docker,稳步改进咱们的流程,并让咱们的团队能熟悉这些概念。对更自动化的部署工做流进行增量更改,使组织可以更快地实现自动化的优点,部署团队能够更加务实地决定他们在流水线中须要什么。咱们的经历证实Rancher在可行性、自动化、甚至团队协做方面都是成功的。咱们但愿分享这些咱们在Docker应用过程当中得到的经验教训将有助于您本身的应用过程。
欢迎关注Rancher官方微信公众号(RancherLabs),获取第一手技术干货推送;欢迎添加客服微信(RancherLabsChina)为好友,加入Rancher官方技术交流群,获取免费技术支持,与数千Docker/Rancher使用者互动。
9月27日,北京海航万豪酒店,容器技术大会Container Day 2017即将举行。
CloudStack之父、海航科技技术总监、华为PaaS部门部长、恒丰银行科技部总经理、阿里云PaaS工程总监、民生保险CIO······均已加入豪华讲师套餐!
11家已容器落地企业,15位真·云计算大咖,13场纯·技术演讲,结合实战场景,聚焦落地经验。免费参会+超高规格,详细议程及注册连接请戳