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

在这一系列文章的第一篇中,咱们分享了只用Docker时咱们开发的初步的工做流,如何建立一个基础的构建和部署流水线。容器的部署方式再也不是在登录server的时候从内存中输入Docker命令。咱们已经经过Jenkins server实现了镜像的自动化构建。咱们使用脚本将Docker命令进行封装,将其存储到GitHub中而且设置版本。目前咱们正采起措施,经过逐步改善现有过程来实现持续部署。然而,仍有一些痛点须要咱们去解决。在这篇文章中,咱们将看看如何使用Docker Compose 和 Ansible来改善此设计。java

在部署镜像时,工程师须要登陆到服务器,并从shell运行咱们的Docker wrapper脚本。这不是很好的解决方法,由于它也须要开发者进行等待。没有任何一方会从在这种方式中获益(做为一个工程师,当你去作某件你很了解而且很容易自动化的事情时,你有多少次被打断了?)因为每一次部署都是经过操做者电脑中的SSH会话来执行的,所以部署过程是不可见的。git

若是你对咱们的部署脚本还有印象,你会发现它看起来像下面的代码段:docker

图片描述

实际上,咱们作的是将Docker run命令语句进行抽象,由此工程师将不须要知道每一个图像成功运行时所须要的确切的参数。虽然这改善了必须所有记住而且手动输入全部Docker参数的现状,但同时也会带来新的问题:shell

  • 每一个容器的逻辑都存储在同一文件中,这使得对应用程序部署逻辑的更改更难追踪;
  • 当开发者须要测试或者修改参数时,须要被迫理清脚本中的逻辑,而不是可以在某一特定的程序中轻松地阅读和修改参数。

在咱们的工做流中,Docker Compose是一个更适合使用的工具,它一样能够将部署参数进行编码,而且在YAML文件中指定,此文件就是docker-compose.yml。Docker Compose不只帮助咱们解决了上面提到的难点,并且也可使咱们从社区将来的工做中获益。下面让咱们理清部署脚本,而且为咱们的JAVA程序示例建立一个Compose文件。首先,咱们须要基于原来的部署逻辑建立一个docker-compose.yml文件:segmentfault

图片描述

如今,部署容器只须要在与docker-compose.yml文件相同目录下输入如下命令:安全

docker-compose up

它将根据compose文件中设置的参数启动一个容器。在compose文件中一个重要的变量是${VERSION} 。Docker Compose能够从当前的shell环境中插入compose文件里所列出的参数。咱们能够经过简单地运行如下语句来设置参数:服务器

VERSION=1.0.0 docker-compose up

它将从咱们的私有镜像仓库挑出标记1.0.0的镜像,以此启动java-service-1程序。若是没有设置VERSION变量,Docker Compose将产生一条警告信息,而且用空字符串代替变量值,由此,具备最新版本标签的镜像将会被挑出。所以,正确地设置变量是至关重要的。网络

做为开发过程的一部分,咱们但愿开发人员可以在本地创建服务而且测试他们的服务。然而,因为docker-compose.yml指向私有镜像仓库的镜像,运行docker-compose将从最近构建的镜像中开启服务而不是从本地资源中开启。理想状况下,开发者能够经过运行如下代码使用典型的docker-compose工做流:app

图片描述

Docker Compose能在不修改docker-compose.yml文件的状况下,让咱们作到这一点。咱们可使用多个文件来覆盖咱们在本地测试中想要改变的任何参数。在docker-compose.override.yml中,咱们指定一个key而不是一个镜像,而且移除了对VERSION变量的需求。因为这是一个覆盖文件,咱们不须要复制任何额外的设置,如端口设置:socket

图片描述

使用Docker Compose而非部署脚本以后,咱们能够:

  • 在源代码中存储每一个compose文件,这与Dockerfile相似;
  • 再也不须要复杂的部署脚本;
  • 容许开发人员在本地轻松地测试并修改应用程序。

如今咱们有了java-service-1程序的compose文件,咱们能够将它从咱们的部署脚本中删除,所以文件组织与下面的结构相似:

图片描述

此时,咱们仍然没有解决镜像构建和部署之间的问题。在docker-compose.yml文件中包含了全部的部署逻辑,可是它如何在环境中运行直至结束的呢?正好如今咱们在运行与UNIX和TPC socket相关的Docker守护进程,是时候讨论一些与安全有关的问题了。

咱们的状况是,工程师登陆到服务器上,手动运行每一个服务器所需容器的部署脚本。默认状况下,当在局部运行Docker命令时,它将使用UNIX socket /var/run/docker.sock链接Docker守护进程;或者让守护进程监听TCP socket,这容许用户远程链接到每一个Docker守护进程,使得工程师可以像登陆到主机同样运行命令。这为链接方式提供了更大的灵活性,可是没有考虑到一些开销和安全问题:

  • 经过网络链接增长了安全隐患;
  • 增长了对于基于主机或者基于网络的ACLs需求;
  • 保护守护进程须要分布式CA和客户端认证。

另外一种可能的方法是不使用基于UNIX socket的方式运行Docker守护进程,而使用SSH来运行命令。已经创建的ACLs将保护SSH端口,而且它只容许经过SSH受权的特定的用户才能使用Docker守护进程。虽然这不是最简洁的方法,可是它有助于保持较低的运行开销,而且使安全隐患降到最低。这点是很是重要的,尤为是对于细粒度的稀疏的任务队列而言。

为了有利于经过SSH运行Docker命令,咱们可使用Ansible——一个流行的编排和配置管理工具。它是无代理的,而且容许经过SSH链接运行“剧本”(服务器任务集合)。一个运行docker-compose命令的简单的剧本以下所示:

图片描述

若是你对Ansible没有过多了解,你也许能够经过上面的剧本大体了解到咱们想作什么。它们按顺序一步步执行,具体以下所示:

  • Ansible将经过SSH链接到目标服务器(容许经过使用DESTINATION变量来指定主机)
  • 在每一个服务器中,Ansible会经过执行shell命令登陆到公司私有的镜像仓库
  • Ansible将位于Jenkins(运行ansible剧本的服务器)中的docker-compose.yml文件复制到每一个目标服务器中的/tmp/docker-compose.yml下
  • 在每一个目标服务器中运行docker-compose命令
  • 经过删除远程的/tmp/docker-compose.yml文件进行清理

一个shell脚本能够被运用在同一个事件中。然而在Ansible中,咱们将很容易的使任务并行化而且获得通过良好测试的模块,经过使Ansible与新的部署剧本相结合,咱们能够远程启动容器,相较于工程师登陆到主机、人工运行命令,这是一个重要的进步。为了在部署过程和状态中提供更大的可视性,咱们将创建Jenkins任务来运行Ansible代码。经过使用Jenkins,在将来咱们能够轻松地将构建和部署任务集成起来,从而获得额外的好处。

Jenkins任务须要两个参数:目标主机(传递给剧本中的DESTINATION变量)和部署镜像的版本(在docker-compose.yml文件中插入VERSION变量)。大多数任务的构建部分是一个shell构建器,它将试图找到程序中的docker-compose.yml文件,而后经过传递变量(用-e)到剧本中,运行ansible-playbook命令:

图片描述

虽然看起来咱们彷佛只对工做流作了微小的变化,可是咱们正一步一步地向构建一个持续部署模型迈进:

  • 部署是能够被审查的。咱们使用日志来记录输出什么、什么时候输出、以及哪些主机是目标主机等信息,这一切都归功于Jenkins。
  • 程序部署逻辑已经从一个单一的脚本分散到存储在程序源代码中的单独的docker-compose.yml文件中,这意味着咱们能够轻松地经过git更改程序部署逻辑。在程序源文件或者部署文件发生变化时,咱们也能够容易地进行构建和部署。

虽然这些改进解决了某些问题,可是它们所带来的新的问题也成为了焦点:

  • 哪一个容器的哪一个版本会被部署到何地?
  • 容器在被部署后会处于哪一种状态?
  • 咱们如何肯定哪一个主机成为程序的目标主机?

在这一系列接下来的文章中,咱们将探讨怎样运行Rancher以及使用它的缘由,尤为是它如何解决上述的问题。与此同时,咱们也讨论它在业务和开发团队中所起到的意想不到的桥梁做用。


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

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

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

图片描述

相关文章
相关标签/搜索