如何使用Docker、Docker-Compose和Rancher搭建部署Pipeline(三)

在这一部分,咱们将一步步的走进Rancher,细致的探讨Rancher将如何解决在部署与容器管理时出现的种种的问题。回顾教程的第二部分,你会发现咱们已经将应用的部署迁移至Docker Compose,而且已经创建了一系列工做步骤来部署咱们的应用。这将使得开发人员可以轻松的对他们的应用部署逻辑进行修正,运维人员也能够查看应用的部署时间。固然,在上一个部分教程的一系列操做中,也存在一些显而易见的问题须要解决。java

使用Docker-Compose时面临的挑战

首先,运维人员必须手动地调整全部服务的执行计划。部署人员须要决定将哪个应用部署至哪一台主机,这意味着部署人员须要时刻对每一台主机的剩余可用资源都有了解,若是某一台主机或者容器崩溃了,部署的操做人员将须要对应用进行从新部署。实际生产中,这意味着主机经常处于负载失衡的状态,而且服务在崩溃以后须要很长时间才能获得恢复。python

其次,使用Docker-Compose时,想要得到你的服务的当前状态是十分困难的。举个例子来讲,咱们常常会从运维人员、项目经理以及开发者口中听到这样的问题:“如今部署环境中运行的究竟是XX应用程序的哪一个版本?”若是咱们采用的是手动调整服务的执行计划的方式,想要获得这个问题的答案一般须要询问指定的进行操做的工程师,工程师们须要登录服务器并运行docker中的ps命令来查看容器的信息。然而面对这些问题,Rancher将会给咱们提供极大的便利:每一个人均可以很是容易地获取已经部署的服务的信息,而不须要临时请求运维人员的帮助。git

使用Rancher以前,咱们试着了解过很多其余可以管理Docker主机或集群的解决方案。然而这些解决方案都没有注意到这是对Docker主机或集群在多种环境(multi-environment)下的管理,这将成为最大的麻烦与负担之一。若是有服务以不一样的负载运行在8种不一样的环境下,咱们须要的是一个统一的方式来管理集群,而不会想要访问8个不一样的服务。而且,咱们但愿让从新构建环境对于咱们而言,变成分分钟就能完成的任务,这样开发者就能够随意地更改开发环境。然而,对于生产环境而言,咱们但愿提供给他们的只是有限的只读访问权限。面对这样的需求,一个采用基于角色的访问控制(RBAC)模型的集中管理方案就显得十分必要了。咱们最初决定尝试Rancher就是由于它在部署上很是简单。github

当Rancher面临这些挑战

在短短半天的时间里,使用AWS ELB、Elasticache、RDS和现有的Docker主机,咱们已经将Rancher部署好并成功运行。可以方便地配置认证信息也是Rancher的优势之一docker

咱们并不会深刻Rancher自己部署的细节,Rancher部署文档中已经说的很明白了。相反,咱们将从刚刚完成初始设置那一步开始,说明将如何将原有的设置(教程第一部分第二部分中所说起的)迁移进来。shell

咱们就从建立不一样的环境开始吧,为了使得这个过程尽可能简单些,咱们将对开发环境(dev)、部署环境(stage)以及生产环境(prod)分别进行设置。每一个环境都已有运行在Ubuntu之上的Docker主机,且这些Docker主机是由内部的Ansible配置的,Ansible安装了Docker、咱们的监控代理、并进行了一些组织特定的更改。在Rancher上,你只须要运行一条命令,将Docker主机在Rancher server内部进行注册,就能够将已有的Docker主机添加至每一个环境中。json

添加一台Rancher主机

在大多数状况下,想要添加一台主机须要通过一系列的操做:经过鼠标在网页上完成一些点击,接下来切换至某个特定的环境,最后在终端系统上输入命令。然而,若是你使用Rancher API,咱们能够在Ansible工具的帮助下使得这一系列的操做转化为彻底自动化的设置。出于好奇,在下面咱们截取了playbook中有关这一操做的部份内容(大可能是根据 Hussein Galas的repo中的内容作出的逻辑上的修改而获得的)。后端

name: install dependencies for uri module
  apt: name=python-httplib2 update_cache=yes
name: check if the rancher-agent is running
  command: docker ps –filter ‘name=rancher-agent’
  register: containers
name: get registration command from rancher
  uri:
    method: GET
    user: “{{ RANCHER_API_KEY }}”
    password: “{{ RANCHER_SECRET_KEY }}”
    force_basic_auth: yes
    status_code: 200
    url: “https://rancher.abc.net/v1/projects/{{ RANCHER_PROJECT_ID }}/registrationtokens”
    return_content: yes
    validate_certs: yes
  register: rancher_token_url
  when: “‘rancher-agent’ not in containers.stdout”
name: register the host machine with rancher
  shell: >
    docker run -d –privileged
    -v /var/run/docker.sock:/var/run/docker.sock
    {{ rancher_token_url.json[‘data’][0][‘image’] }}
    {{ rancher_token_url.json[‘data’][0][‘command’].split() | last}}
  when: “‘rancher-agent’ not in containers.stdout”

随着工做的一步步进行,咱们已经完成了环境的建立并已经将主机在Rancher server中注册,如今就让咱们来了解一下,如何将咱们的部署工做流整合至Rancher中。咱们知道,对于每一台Docker来讲,其中都有着一些正在运行的容器,这些系统的部署是经过Ansible工具借助Jenkins完成的。Rancher提供了如下开箱即用的功能:服务器

  • 管理已有的容器(好比:启动、修改、查看日志、启动一个交互式的shell)
  • 得到关于运行中的和中止运行的容器的信息(好比:镜像信息、初始化命令信息、命令信息,端口映射信息以及环境变量信息)
  • 查看主机和容器层级上的资源使用状况(好比:CPU使用率、内存占用率、以及磁盘和网络的使用状况)

独立的容器微信

很快,咱们就已经将Docker主机注册至Rancher Server中,如今咱们能够查看容器在各类环境下的运行状态信息了。不只如此,若是想要将这些信息分享给其余团队,咱们仅仅须要针对某个环境给予他们一些有限的权限。经过以上的方式,在想要得到状态信息时咱们就彻底没有必要请求操做人员登陆Docker主机,再经过人工的方式去查询,同时这样也减小了申请得到环境信息的请求的数目,由于咱们已经将某些访问权限分配至各个团队了。举个例子来讲,若是为开发团队分配环境信息的只读权限,那么将会在开发团队与部署操做团队之间架起一座沟通的桥梁,这样两个团队都会对这个环境的状态比以往更加的关心。在这个基础上,故障的排除也变成了一种小组间相互合做的过程,而不是以往的那种单向的、依赖同步信息流的解决方式,相互合做的方式也会减小解决突发事件的总时间。

到如今为止,咱们已经将已有的Docker主机加入Rancher Server,而且基于已经阅读完了的教程的第一部分关于Jenkins和Rancher的内容,下一步,咱们打算改进的部分是咱们已有的部署流水线,咱们将会对已有的部署流水线进行修改,以便于使用Rancher compose,Rancher Compose将代替以前Ansible工具提到的Docker compose。不过在咱们深刻下一部分以前,咱们首先须要了解关于Rancher的应用、调度、Docker Compose和Rancher Compose的一些信息。

**应用与服务:**Rancher将每一个独立的容器(指的是部署在Rancher以外的容器,或者是经过Rancher UI生成的一次性功能的容器)、应用和服务彼此分离开。简单地说,应用是一组服务,而全部容器都须要利用服务(关于应用和服务的内容以后将会由更加详细的介绍)以构建一个应用。独立的容器须要手动地进行调度。

**调度:**在以前的部署技术中,运维人员须要决定容器应当在哪一台主机上运行。若是使用的是部署脚本,那么意味着运维人员须要决定部署脚本在哪一台或哪几台主机上运行;若是使用Ansible,这将意味着运维人员须要决定哪些主机或组须要到Jenkins中工做。不管是哪种方式,都须要运维人员去作一些决定,可是在大多数状况下,他们作出的决定都缺少一些可靠的依据,这对咱们的部署工做非常不利(好比说某一台主机的CPU使用率高达100%)。不少解决方案,好比像Docker Swarm、Kubernetes、Mesos和Rancher都采用了调度器来解决这类问题。对于须要执行的某个操做,调度器将会请求得到一组主机的信息,并判断出哪几台是适合执行这个操做的。调度器会根据默认的需求设定或者用户定义的特定需求,好比CPU使用率高低、亲和性或反亲和性规则(好比:禁止在同一台主机上部署两个相同容器)等相似的需求,以逐渐缩小主机选择的范围。若是我是一个负责部署的运维人员,调度器将会极大的减小个人工做负担(尤为是我在深夜加班忙于部署时),由于调度器对以上信息的计算比我快的多,也准的多。Rancher在咱们经过应用部署服务的时候可以提供一个开箱即用调度器。

**Docker compose:**Rancher使用Docker compose来建立应用并定义服务。因为咱们已经将服务转化为Docker compose的文件,咱们在此基础上建立应用就变得容易了许多。应用能够手动的从UI界面中建立,也能够经过Rancher compose在命令行(CLI)下快速的建立。

**Rancher compose:**Rancher compose是一种经过命令行(CLI)让咱们得以对Rancher中的每一种环境的应用和服务进行方便的管理的工具。同时,经过rancher-compse.yml文件,Rancher compose还能容许对Rancher工具进行一些其余访问。这是一个纯粹的附加的文件,将不会取代原有的docker-compose.yml文件。在rancher-compose.yml文件中,你能够定义如下内容,好比说:

  • 每种服务的升级策略信息
  • 每种服务的健康检查信息
  • 每种服务的需求规模信息

这些都是Rancher中很是实用的亮点,若是你使用Docker Compose或者Docker daemon,这些内容你都是获取不到的。若是想要查看Rancher Compose能提供的全部特性,你能够查看这个文档

经过将已有的部署工做交给Rancher Compose来替代以前的Ansible工具,咱们可以很轻松的将服务迁移并部署为Rancher应用的形式。以后,咱们就可以去除DESTINATION参数了,但咱们依然保留VERSION参数,由于咱们在插入docker-compose.uml文件的时候还要使用它。如下是使用Jenkins部署时,部署逻辑的shell片断:

export RANCHER_URL=http://rancher.abc.net/
export RANCHER_ACCESS_KEY=…
export RANCHER_SECRET_KEY=…

if [ -f docker/docker-compose.yml ]; then
  docker_dir=docker
elif [ -f /opt/abc/dockerfiles/java-service-1/docker-compose.yml ]; then
  docker_dir=/opt/abc/dockerfiles/java-service-1
else
  echo “No docker-compose.yml found. Can’t continue!”
  exit 1
fi

if ! [ -f ${docker_dir}/rancher-compose.yml ]; then
  echo “No rancher-compose.yml found. Can’t continue!”
  exit 1
fi

/usr/local/bin/rancher-compose –verbose \
  -f ${docker_dir}/docker-compose.yml \
  -r ${docker_dir}/rancher-compose.yml \
  up -d –upgrade

阅读完代码段,咱们能够发现其主要包括如下内容:

  1. 咱们定义了以环境变量的方式如何访问咱们的Rancher server。
  2. 须要找到docker-compose.yml文件,不然将会任务将会报错退出。
  3. 须要找到rancher-compose.yml文件,不然任务将会报错退出。
  4. 运行Rancher-compose,并告诉它不要block而且使用-d命令输出日志,使用-upgrade命令更新一个已经存在的服务。

也许你已经发现了,在绝大部分,代码的逻辑都是相同的,而最大的区别就是使用rancher-compose代替使用Ansible工具完成部署,并对每个服务添加了rancher-compose.yml文件。具体到咱们的java-service-1应用,docker-compose文件和rancher-compose文件如今是这样的:

docker-compose.yml
java-service-1:
image: registry.abc.net/java-service-1:${VERSION}
container_name: java-service-1
expose:
– 8080
ports:
– 8080:8080
rancher-compose.yml
java-service-1:
scale: 3

在开始部署工做以前,咱们先回顾一下部署工做的流程:

  • 开发人员将代码的修改推送至git上
  • 使用Jenkins对代码进行单元测试,在测试工做结束以后触发下游工做
  • 下游工做采用新的代码构建一个docker镜像,并将其推送至咱们本身的Docker镜像仓库中
  • 建立包含应用名、版本号、部署环境的deployment ticket
DEPLOY-111:
  App: JavaService1, branch “release/1.0.1”
  Environment: Production

部署工程师针对应用运行Jenkins的部署工做,运行时须要将版本号做为参数。 Rancher compose开始运行,对于某个环境建立或更新应用,而且当达到所需规模的时候,结束这个工做 部署工程师以及开发工程师分别手动地对服务进行校验 部署工程师在Rancher UI中确认完成升级

关键点

**使用Rancher进行咱们的服务部署时,咱们从Rancher内建的调度、弹性伸缩、还原、升级、和回滚等工具中得到极大的便利,使得咱们在部署过程当中没有花太大的力气。**同时咱们发现,在将部署工做从Ansible工具中迁移至Rancher的工做量也是很小的,仅仅须要在原有的基础上增长rancher-compose.yml文件。然而,使用Rancher来处理咱们容器的调度意味着咱们将难以确认咱们的应用究竟是在哪台主机上运行的。比方说,以前咱们并无决定java-service-1应用在哪里运行,对于后端,在进行负载均衡相关操做时,该应用就没有一个静态的IP。咱们须要找到一种办法,使得咱们的各类应用之间可以相互察觉到对方。最终,对于咱们的java-service-1应用,咱们将明确地将应用容器所在的docker主机的8080端口与应用绑定,不过,若是有其余服务与应用绑定为相同的端口,它将会启动失败。一般负责调度决策的工程师将会对以上的事务进行处理。然而,咱们最好将这些信息通知调度器以免这样的事情发生。

在本教程的最后一个部分,咱们将继续探索一些方案来解决在使用亲和性规则、主机标签、服务探索以及智能升级和回滚等特性时出现的问题。

欢迎关注Rancher官方微信公众号(RancherLabs),获取第一手技术干货推送;欢迎添加客服微信(RancherLabsChina)为好友,加入Rancher官方技术交流群,获取免费技术支持,与数千Docker/Rancher使用者互动。

9月27日,北京海航万豪酒店,容器技术大会Container Day 2017即将举行。

CloudStack之父、海航科技技术总监、华为PaaS部门部长、恒丰银行科技部总经理、阿里云PaaS工程总监、民生保险CIO······均已加入豪华讲师套餐!

11家已容器落地企业,15位真·云计算大咖,13场纯·技术演讲,结合实战场景,聚焦落地经验。免费参会+超高规格,详细议程及注册连接请戳 输入图片说明

相关文章
相关标签/搜索